@igxjs/node-components 1.0.7 → 1.0.8
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 +68 -510
- package/components/jwt.js +10 -10
- package/docs/README.md +54 -0
- package/docs/flex-router.md +167 -0
- package/docs/http-handlers.md +302 -0
- package/docs/jwt-manager.md +124 -0
- package/docs/redis-manager.md +210 -0
- package/docs/session-manager.md +160 -0
- package/index.d.ts +3 -2
- package/package.json +1 -1
- package/tests/jwt.test.js +345 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Node Components
|
|
2
2
|
|
|
3
|
-
Shared components for Express.js applications providing session management, routing utilities, error handling, and Redis integration.
|
|
3
|
+
Shared components for Express.js applications providing session management, routing utilities, error handling, JWT authentication, and Redis integration.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,559 +8,112 @@ Shared components for Express.js applications providing session management, rout
|
|
|
8
8
|
npm install @igxjs/node-components
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Components
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
| Component | Description | Documentation |
|
|
14
|
+
|-----------|-------------|---------------|
|
|
15
|
+
| **SessionManager** | SSO session management with Redis/memory storage | [View docs](./docs/session-manager.md) |
|
|
16
|
+
| **FlexRouter** | Flexible routing with context paths and middleware | [View docs](./docs/flex-router.md) |
|
|
17
|
+
| **RedisManager** | Redis connection management with TLS support | [View docs](./docs/redis-manager.md) |
|
|
18
|
+
| **JWT Manager** | Secure JWT encryption/decryption with JWE | [View docs](./docs/jwt-manager.md) |
|
|
19
|
+
| **HTTP Handlers** | Standardized error handling and status codes | [View docs](./docs/http-handlers.md) |
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
## Quick Start Examples
|
|
16
22
|
|
|
17
|
-
|
|
23
|
+
### SessionManager
|
|
18
24
|
|
|
19
25
|
```javascript
|
|
20
|
-
// Example configuration object
|
|
21
|
-
// All fields are strings except SESSION_AGE which is a number
|
|
22
|
-
|
|
23
|
-
const config = {
|
|
24
|
-
// SSO Configuration
|
|
25
|
-
SSO_ENDPOINT_URL: 'https://sso.example.com',
|
|
26
|
-
SSO_CLIENT_ID: 'your-client-id',
|
|
27
|
-
SSO_CLIENT_SECRET: 'your-client-secret',
|
|
28
|
-
SSO_SUCCESS_URL: '/dashboard',
|
|
29
|
-
SSO_FAILURE_URL: '/login',
|
|
30
|
-
|
|
31
|
-
// Session Configuration
|
|
32
|
-
SESSION_AGE: 64800000, // 18 hours in milliseconds
|
|
33
|
-
SESSION_COOKIE_PATH: '/',
|
|
34
|
-
SESSION_SECRET: 'your-session-secret',
|
|
35
|
-
SESSION_PREFIX: 'ibmid:', // Default value when not provided
|
|
36
|
-
|
|
37
|
-
// Redis Configuration (optional - uses memory store if not provided)
|
|
38
|
-
REDIS_URL: 'redis://localhost:6379',
|
|
39
|
-
REDIS_CERT_PATH: '/path/to/cert.pem' // For TLS connections
|
|
40
|
-
};
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
#### Usage Example
|
|
44
|
-
|
|
45
|
-
```javascript
|
|
46
|
-
import express from 'express';
|
|
47
26
|
import { SessionManager } from '@igxjs/node-components';
|
|
48
27
|
|
|
49
|
-
|
|
50
|
-
const session = new SessionManager(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
...user,
|
|
57
|
-
displayName: user.email?.split('@')[0],
|
|
58
|
-
hasAdminAccess: user.authorized && user.email?.endsWith('@admin.com')
|
|
59
|
-
};
|
|
28
|
+
// Create singleton instance
|
|
29
|
+
export const session = new SessionManager({
|
|
30
|
+
SSO_ENDPOINT_URL: process.env.SSO_ENDPOINT_URL,
|
|
31
|
+
SSO_CLIENT_ID: process.env.SSO_CLIENT_ID,
|
|
32
|
+
SSO_CLIENT_SECRET: process.env.SSO_CLIENT_SECRET,
|
|
33
|
+
SESSION_SECRET: process.env.SESSION_SECRET,
|
|
34
|
+
REDIS_URL: process.env.REDIS_URL
|
|
60
35
|
});
|
|
61
36
|
|
|
62
|
-
//
|
|
37
|
+
// Setup in your app
|
|
38
|
+
await session.setup(app, (user) => ({ ...user, displayName: user.email }));
|
|
39
|
+
|
|
40
|
+
// Protect routes
|
|
63
41
|
app.get('/protected', session.authenticate(), (req, res) => {
|
|
64
42
|
res.json({ user: req.user });
|
|
65
43
|
});
|
|
66
|
-
|
|
67
|
-
// SSO callback endpoint
|
|
68
|
-
app.get('/auth/callback', session.callback((user) => {
|
|
69
|
-
// Initialize user object after successful login
|
|
70
|
-
return {
|
|
71
|
-
...user,
|
|
72
|
-
loginTime: new Date()
|
|
73
|
-
};
|
|
74
|
-
}));
|
|
75
|
-
|
|
76
|
-
// Get available identity providers
|
|
77
|
-
app.get('/auth/providers', session.identityProviders());
|
|
78
|
-
|
|
79
|
-
// Refresh user session
|
|
80
|
-
app.post('/auth/refresh', session.refresh((user) => {
|
|
81
|
-
return { ...user, refreshedAt: new Date() };
|
|
82
|
-
}));
|
|
83
|
-
|
|
84
|
-
// Logout endpoint
|
|
85
|
-
app.get('/auth/logout', session.logout());
|
|
86
44
|
```
|
|
87
45
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
- **`setup(app, updateUser)`** - Initialize session configurations
|
|
91
|
-
- **`authenticate(isDebugging?, redirectUrl?)`** - Resource protection middleware
|
|
92
|
-
- **`callback(initUser)`** - SSO callback handler for successful login
|
|
93
|
-
- **`identityProviders()`** - Get available identity providers
|
|
94
|
-
- **`logout()`** - Application logout handler (not SSO logout)
|
|
95
|
-
- **`refresh(initUser)`** - Refresh user session with new token
|
|
96
|
-
- **`redisManager()`** - Get the RedisManager instance (returns RedisManager or null)
|
|
97
|
-
- **`hasLock(email)`** - Check if email has a session refresh lock
|
|
98
|
-
- **`lock(email)`** - Lock email for session refresh (prevents concurrent refreshes)
|
|
99
|
-
- **`clearLocks()`** - Clear expired session refresh locks
|
|
46
|
+
[📖 Full SessionManager Documentation](./docs/session-manager.md)
|
|
100
47
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
### 2. FlexRouter
|
|
104
|
-
|
|
105
|
-
A flexible routing utility for Express.js that allows mounting routers with custom context paths and middleware handlers.
|
|
106
|
-
|
|
107
|
-
#### Usage Example
|
|
48
|
+
### FlexRouter
|
|
108
49
|
|
|
109
50
|
```javascript
|
|
110
51
|
import { Router } from 'express';
|
|
111
52
|
import { FlexRouter } from '@igxjs/node-components';
|
|
112
|
-
// Assuming you have an authenticate middleware
|
|
113
|
-
// import { authenticate } from './middlewares/auth.js';
|
|
114
|
-
|
|
115
|
-
// Create routers
|
|
116
|
-
const publicRouter = Router();
|
|
117
|
-
const privateRouter = Router();
|
|
118
|
-
|
|
119
|
-
publicRouter.get('/health', (req, res) => {
|
|
120
|
-
res.send('OK');
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
privateRouter.get('/users', (req, res) => {
|
|
124
|
-
res.json({ users: [] });
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// Define flex routers with context paths and optional middleware
|
|
128
|
-
export const routers = [
|
|
129
|
-
new FlexRouter('/api/v1/public', publicRouter),
|
|
130
|
-
new FlexRouter('/api/v1/protected', privateRouter, [authenticate]), // with middleware
|
|
131
|
-
];
|
|
132
53
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const basePath = '';
|
|
136
|
-
|
|
137
|
-
routers.forEach(router => {
|
|
138
|
-
router.mount(app, basePath);
|
|
139
|
-
});
|
|
54
|
+
const apiRouter = Router();
|
|
55
|
+
apiRouter.get('/users', (req, res) => res.json({ users: [] }));
|
|
140
56
|
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
57
|
+
// Mount with context path and middleware
|
|
58
|
+
const flexRouter = new FlexRouter('/api/v1', apiRouter, [authenticate]);
|
|
59
|
+
flexRouter.mount(app, '');
|
|
144
60
|
```
|
|
145
61
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
- **`constructor(context, router, handlers?)`** - Create a new FlexRouter
|
|
149
|
-
- `context` (string) - The context path for the router
|
|
150
|
-
- `router` - Express Router instance
|
|
151
|
-
- `handlers` - Optional array of middleware handlers
|
|
152
|
-
|
|
153
|
-
- **`mount(app, basePath)`** - Mount the router to an Express application
|
|
154
|
-
- `app` - Express application instance
|
|
155
|
-
- `basePath` (string) - Base path to prepend to the context
|
|
156
|
-
|
|
157
|
-
---
|
|
158
|
-
|
|
159
|
-
### 3. RedisManager
|
|
62
|
+
[📖 Full FlexRouter Documentation](./docs/flex-router.md)
|
|
160
63
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
* Note: the RedisManager is used internally by the `SessionManager`, so you don't need to use it directly.
|
|
164
|
-
|
|
165
|
-
#### Usage Example
|
|
166
|
-
|
|
167
|
-
```javascript
|
|
168
|
-
import { RedisManager } from '@igxjs/node-components';
|
|
169
|
-
|
|
170
|
-
const redisManager = new RedisManager();
|
|
171
|
-
|
|
172
|
-
// Connect to Redis (with optional TLS certificate)
|
|
173
|
-
const connected = await redisManager.connect(
|
|
174
|
-
'rediss://localhost:6379',
|
|
175
|
-
'/path/to/cert.pem'
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
if (connected) {
|
|
179
|
-
// Get Redis client for direct operations
|
|
180
|
-
const client = redisManager.getClient();
|
|
181
|
-
await client.set('key', 'value');
|
|
182
|
-
|
|
183
|
-
// Check connection status
|
|
184
|
-
const isConnected = await redisManager.isConnected();
|
|
185
|
-
|
|
186
|
-
// Disconnect when done
|
|
187
|
-
await redisManager.disConnect();
|
|
188
|
-
}
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
#### API Methods
|
|
192
|
-
|
|
193
|
-
- **`connect(redisUrl, certPath)`** - Connect to Redis server
|
|
194
|
-
- Returns: `Promise<boolean>` - Returns true if connected successfully
|
|
195
|
-
- Supports both `redis://` and `rediss://` (TLS) URLs
|
|
196
|
-
- Automatically handles TLS certificate loading when using `rediss://`
|
|
197
|
-
|
|
198
|
-
- **`getClient()`** - Get the Redis client instance
|
|
199
|
-
- Returns: Redis client for direct operations
|
|
200
|
-
|
|
201
|
-
- **`isConnected()`** - Check if Redis connection is active
|
|
202
|
-
- Returns: `Promise<boolean>` - Returns true if connected and responsive
|
|
203
|
-
|
|
204
|
-
- **`disConnect()`** - Disconnect from Redis server
|
|
205
|
-
- Returns: `Promise<void>`
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
### 4. JWT Manager
|
|
210
|
-
|
|
211
|
-
Provides JWT (JSON Web Token) encryption and decryption utilities using the `jose` library with JWE (JSON Web Encryption) for secure token management.
|
|
212
|
-
|
|
213
|
-
#### Configuration Options
|
|
214
|
-
|
|
215
|
-
```javascript
|
|
216
|
-
// Example configuration object
|
|
217
|
-
const jwtOptions = {
|
|
218
|
-
algorithm: 'dir', // JWE algorithm (default: 'dir')
|
|
219
|
-
encryption: 'A256GCM', // JWE encryption method (default: 'A256GCM')
|
|
220
|
-
expirationTime: '10m', // Token expiration (default: '10m')
|
|
221
|
-
clockTolerance: 30, // Clock tolerance in seconds (default: 30)
|
|
222
|
-
secretHashAlgorithm: 'SHA-256', // Hash algorithm for secret derivation (default: 'SHA-256')
|
|
223
|
-
issuer: 'your-app', // Optional JWT issuer claim
|
|
224
|
-
audience: 'your-users', // Optional JWT audience claim
|
|
225
|
-
subject: 'user-session' // Optional JWT subject claim
|
|
226
|
-
};
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
#### Usage Example
|
|
64
|
+
### JWT Manager
|
|
230
65
|
|
|
231
66
|
```javascript
|
|
232
67
|
import { JwtManager } from '@igxjs/node-components';
|
|
233
68
|
|
|
234
|
-
|
|
235
|
-
const jwtManager = new JwtManager({
|
|
236
|
-
expirationTime: '1h',
|
|
237
|
-
issuer: 'my-app',
|
|
238
|
-
audience: 'my-users'
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
// Encrypt user data
|
|
242
|
-
const userData = {
|
|
243
|
-
userId: '12345',
|
|
244
|
-
email: 'user@example.com',
|
|
245
|
-
roles: ['admin', 'user']
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
const secret = 'your-secret-key';
|
|
249
|
-
const token = await jwtManager.encrypt(userData, secret);
|
|
250
|
-
|
|
251
|
-
console.log('Encrypted Token:', token);
|
|
252
|
-
|
|
253
|
-
// Decrypt token
|
|
254
|
-
try {
|
|
255
|
-
const result = await jwtManager.decrypt(token, secret);
|
|
256
|
-
console.log('Decrypted Payload:', result.payload);
|
|
257
|
-
console.log('Protected Header:', result.protectedHeader);
|
|
258
|
-
} catch (error) {
|
|
259
|
-
console.error('Token validation failed:', error);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Override options per-call
|
|
263
|
-
const shortLivedToken = await jwtManager.encrypt(
|
|
264
|
-
userData,
|
|
265
|
-
secret,
|
|
266
|
-
{ expirationTime: '5m' } // Override default expiration
|
|
267
|
-
);
|
|
268
|
-
|
|
269
|
-
// Decrypt with custom validation
|
|
270
|
-
const validatedResult = await jwtManager.decrypt(
|
|
271
|
-
token,
|
|
272
|
-
secret,
|
|
273
|
-
{
|
|
274
|
-
clockTolerance: 60, // Allow more clock skew
|
|
275
|
-
issuer: 'my-app', // Validate issuer
|
|
276
|
-
audience: 'my-users' // Validate audience
|
|
277
|
-
}
|
|
278
|
-
);
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
#### Advanced Usage with Express
|
|
282
|
-
|
|
283
|
-
```javascript
|
|
284
|
-
import express from 'express';
|
|
285
|
-
import { JwtManager } from '@igxjs/node-components';
|
|
286
|
-
|
|
287
|
-
const app = express();
|
|
288
|
-
const jwt = new JwtManager({ expirationTime: '24h' });
|
|
69
|
+
const jwt = new JwtManager({ expirationTime: '1h' });
|
|
289
70
|
const SECRET = process.env.JWT_SECRET;
|
|
290
71
|
|
|
291
|
-
//
|
|
292
|
-
|
|
293
|
-
try {
|
|
294
|
-
const { username, password } = req.body;
|
|
295
|
-
|
|
296
|
-
// Verify credentials (your logic here)
|
|
297
|
-
const user = await verifyCredentials(username, password);
|
|
298
|
-
|
|
299
|
-
// Create JWT token
|
|
300
|
-
const token = await jwt.encrypt({
|
|
301
|
-
sub: user.id,
|
|
302
|
-
email: user.email,
|
|
303
|
-
roles: user.roles
|
|
304
|
-
}, SECRET);
|
|
305
|
-
|
|
306
|
-
res.json({ token });
|
|
307
|
-
} catch (error) {
|
|
308
|
-
next(error);
|
|
309
|
-
}
|
|
310
|
-
});
|
|
72
|
+
// Create token
|
|
73
|
+
const token = await jwt.encrypt({ userId: '123', email: 'user@example.com' }, SECRET);
|
|
311
74
|
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
try {
|
|
315
|
-
const token = req.headers.authorization?.replace('Bearer ', '');
|
|
316
|
-
|
|
317
|
-
if (!token) {
|
|
318
|
-
return res.status(401).json({ error: 'No token provided' });
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Decrypt and validate token
|
|
322
|
-
const { payload } = await jwt.decrypt(token, SECRET);
|
|
323
|
-
|
|
324
|
-
res.json({ user: payload });
|
|
325
|
-
} catch (error) {
|
|
326
|
-
// Token expired or invalid
|
|
327
|
-
res.status(401).json({ error: 'Invalid or expired token' });
|
|
328
|
-
}
|
|
329
|
-
});
|
|
75
|
+
// Verify token
|
|
76
|
+
const { payload } = await jwt.decrypt(token, SECRET);
|
|
330
77
|
```
|
|
331
78
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
**Constructor:**
|
|
335
|
-
- **`new JwtManager(options?)`** - Create a new JwtManager instance
|
|
336
|
-
- `options` (JwtManagerOptions, optional) - Configuration options
|
|
337
|
-
- All options are optional and have sensible defaults
|
|
338
|
-
|
|
339
|
-
**Methods:**
|
|
340
|
-
- **`encrypt(data, input, options?)`** - Generate encrypted JWT token
|
|
341
|
-
- `data` (JWTPayload) - User data payload to encrypt
|
|
342
|
-
- `input` (string) - Secret key or password for encryption
|
|
343
|
-
- `options` (JwtEncryptOptions, optional) - Per-call configuration overrides
|
|
344
|
-
- Returns: `Promise<string>` - Encrypted JWT token
|
|
345
|
-
|
|
346
|
-
- **`decrypt(token, input, options?)`** - Decrypt and validate JWT token
|
|
347
|
-
- `token` (string) - JWT token to decrypt
|
|
348
|
-
- `input` (string) - Secret key or password for decryption
|
|
349
|
-
- `options` (JwtDecryptOptions, optional) - Per-call configuration overrides
|
|
350
|
-
- Returns: `Promise<JWTDecryptResult>` - Object containing `payload` and `protectedHeader`
|
|
351
|
-
|
|
352
|
-
#### Configuration Details
|
|
353
|
-
|
|
354
|
-
**Algorithms:**
|
|
355
|
-
- `'dir'` (default) - Direct encryption with shared symmetric key
|
|
356
|
-
- `'A128KW'`, `'A192KW'`, `'A256KW'` - AES Key Wrap algorithms
|
|
357
|
-
|
|
358
|
-
**Encryption Methods:**
|
|
359
|
-
- `'A256GCM'` (default) - AES-GCM with 256-bit key
|
|
360
|
-
- `'A128GCM'`, `'A192GCM'` - AES-GCM with 128/192-bit keys
|
|
79
|
+
[📖 Full JWT Manager Documentation](./docs/jwt-manager.md)
|
|
361
80
|
|
|
362
|
-
|
|
363
|
-
- `'10m'` - 10 minutes
|
|
364
|
-
- `'1h'` - 1 hour
|
|
365
|
-
- `'7d'` - 7 days
|
|
366
|
-
- `'30s'` - 30 seconds
|
|
367
|
-
|
|
368
|
-
**JWT Claims:**
|
|
369
|
-
- `issuer` (iss) - Token issuer identification
|
|
370
|
-
- `audience` (aud) - Intended token recipient
|
|
371
|
-
- `subject` (sub) - Token subject (usually user ID)
|
|
372
|
-
|
|
373
|
-
---
|
|
374
|
-
|
|
375
|
-
### 5. HTTP Handlers
|
|
376
|
-
|
|
377
|
-
Custom error handling utilities with standardized HTTP status codes and error responses.
|
|
378
|
-
|
|
379
|
-
#### Available Exports
|
|
81
|
+
### HTTP Handlers
|
|
380
82
|
|
|
381
83
|
```javascript
|
|
382
|
-
import {
|
|
383
|
-
|
|
84
|
+
import {
|
|
85
|
+
httpCodes,
|
|
384
86
|
httpError,
|
|
385
87
|
httpErrorHandler,
|
|
386
|
-
httpNotFoundHandler
|
|
387
|
-
httpCodes,
|
|
388
|
-
httpMessages,
|
|
389
|
-
httpHelper
|
|
88
|
+
httpNotFoundHandler
|
|
390
89
|
} from '@igxjs/node-components';
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
#### Usage Examples
|
|
394
90
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
```javascript
|
|
398
|
-
// Using CustomError class
|
|
399
|
-
throw new CustomError(httpCodes.BAD_REQUEST, 'Invalid input data');
|
|
400
|
-
|
|
401
|
-
// Using httpError helper function (alias for new CustomError)
|
|
402
|
-
throw httpError(httpCodes.BAD_REQUEST, 'Invalid input data');
|
|
403
|
-
|
|
404
|
-
// With error details and additional data
|
|
405
|
-
throw new CustomError(
|
|
406
|
-
httpCodes.UNAUTHORIZED,
|
|
407
|
-
'Authentication failed',
|
|
408
|
-
{ originalError: err },
|
|
409
|
-
{ attemptedEmail: email }
|
|
410
|
-
);
|
|
411
|
-
|
|
412
|
-
// Using httpError with additional data
|
|
413
|
-
throw httpError(
|
|
414
|
-
httpCodes.UNAUTHORIZED,
|
|
415
|
-
'Authentication failed',
|
|
416
|
-
{ originalError: err },
|
|
417
|
-
{ attemptedEmail: email }
|
|
418
|
-
);
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
**Handling Axios/HTTP Errors:**
|
|
422
|
-
|
|
423
|
-
```javascript
|
|
424
|
-
// Use httpHelper to handle Axios errors
|
|
425
|
-
try {
|
|
426
|
-
await axios.get('https://api.example.com/data');
|
|
427
|
-
} catch (error) {
|
|
428
|
-
// Convert Axios error to CustomError
|
|
429
|
-
throw httpHelper.handleAxiosError(error, 'Failed to fetch data');
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// Or use it in error handling
|
|
91
|
+
// Use in routes
|
|
433
92
|
app.get('/api/data', async (req, res, next) => {
|
|
434
93
|
try {
|
|
435
|
-
const
|
|
436
|
-
res.json(
|
|
94
|
+
const data = await fetchData();
|
|
95
|
+
res.json(data);
|
|
437
96
|
} catch (error) {
|
|
438
|
-
|
|
97
|
+
next(httpError(httpCodes.SYSTEM_FAILURE, 'Failed to fetch data', error));
|
|
439
98
|
}
|
|
440
99
|
});
|
|
441
|
-
```
|
|
442
100
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
```javascript
|
|
446
|
-
import express from 'express';
|
|
447
|
-
import { httpErrorHandler, httpNotFoundHandler } from '@igxjs/node-components';
|
|
448
|
-
|
|
449
|
-
const app = express();
|
|
450
|
-
|
|
451
|
-
// Your routes here
|
|
452
|
-
app.get('/api/data', async (req, res, next) => {
|
|
453
|
-
try {
|
|
454
|
-
// Your logic
|
|
455
|
-
} catch (error) {
|
|
456
|
-
next(error);
|
|
457
|
-
}
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
// Add 404 handler before error handler
|
|
101
|
+
// Add middleware
|
|
461
102
|
app.use(httpNotFoundHandler);
|
|
462
|
-
|
|
463
|
-
// Add error handler as the last middleware
|
|
464
103
|
app.use(httpErrorHandler);
|
|
465
104
|
```
|
|
466
105
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
**Available Status Codes:**
|
|
470
|
-
- `httpCodes.OK` (200)
|
|
471
|
-
- `httpCodes.CREATED` (201)
|
|
472
|
-
- `httpCodes.NO_CONTENT` (204)
|
|
473
|
-
- `httpCodes.BAD_REQUEST` (400)
|
|
474
|
-
- `httpCodes.UNAUTHORIZED` (401)
|
|
475
|
-
- `httpCodes.FORBIDDEN` (403)
|
|
476
|
-
- `httpCodes.NOT_FOUND` (404)
|
|
477
|
-
- `httpCodes.NOT_ACCEPTABLE` (406)
|
|
478
|
-
- `httpCodes.CONFLICT` (409)
|
|
479
|
-
- `httpCodes.LOCKED` (423)
|
|
480
|
-
- `httpCodes.SYSTEM_FAILURE` (500)
|
|
481
|
-
- `httpCodes.NOT_IMPLEMENTED` (501)
|
|
482
|
-
|
|
483
|
-
**Available Status Messages:**
|
|
484
|
-
- Corresponding `httpMessages` constants are available for each status code (e.g., `httpMessages.OK`, `httpMessages.BAD_REQUEST`, etc.)
|
|
485
|
-
|
|
486
|
-
#### CustomError API
|
|
487
|
-
|
|
488
|
-
**Constructor:**
|
|
489
|
-
```javascript
|
|
490
|
-
// new CustomError(code, message, error, data)
|
|
491
|
-
// - code: number - HTTP status code
|
|
492
|
-
// - message: string - Error message
|
|
493
|
-
// - error: object (optional) - Original error object
|
|
494
|
-
// - object (optional) - Additional error data
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
**Properties:**
|
|
498
|
-
- **`code`** - HTTP status code (number)
|
|
499
|
-
- **`message`** - Error message (string)
|
|
500
|
-
- **`error`** - Original error object (if provided)
|
|
501
|
-
- **`data`** - Additional error data (if provided)
|
|
502
|
-
|
|
503
|
-
#### httpError API
|
|
504
|
-
|
|
505
|
-
**Function:**
|
|
506
|
-
- **`httpError(code, message, error?, data?)`** - Convenience function to create CustomError instances
|
|
507
|
-
- `code` (number) - HTTP status code
|
|
508
|
-
- `message` (string) - Error message
|
|
509
|
-
- `error` (object, optional) - Original error object
|
|
510
|
-
- `data` (object, optional) - Additional error data
|
|
511
|
-
- Returns: `CustomError` instance
|
|
512
|
-
- **Note:** This is an alias for `new CustomError()` - use whichever syntax you prefer
|
|
513
|
-
|
|
514
|
-
#### httpErrorHandler API
|
|
515
|
-
|
|
516
|
-
**Middleware Function:**
|
|
517
|
-
- **`httpErrorHandler(err, req, res, next)`** - Express error handling middleware
|
|
518
|
-
- Handles `CustomError` instances and other errors
|
|
519
|
-
- Sets appropriate HTTP status codes and response format
|
|
520
|
-
- Adds CORS headers automatically
|
|
521
|
-
- Logs error details to console
|
|
522
|
-
- **Usage:** Add as the last middleware in your Express app
|
|
523
|
-
|
|
524
|
-
#### httpNotFoundHandler API
|
|
525
|
-
|
|
526
|
-
**Middleware Function:**
|
|
527
|
-
- **`httpNotFoundHandler(req, res, next)`** - Express 404 handler middleware
|
|
528
|
-
- Catches all unmatched routes and returns 404 error
|
|
529
|
-
- Creates a `CustomError` with NOT_FOUND status
|
|
530
|
-
- **Usage:** Add before the error handler middleware
|
|
531
|
-
|
|
532
|
-
#### httpHelper API
|
|
533
|
-
|
|
534
|
-
The `httpHelper` object provides utility methods for error handling:
|
|
535
|
-
|
|
536
|
-
**Methods:**
|
|
537
|
-
|
|
538
|
-
- **`httpHelper.handleAxiosError(error, defaultMessage)`** - Analyze and convert Axios/HTTP errors to CustomError
|
|
539
|
-
- `error` (Error | AxiosError) - The error object to analyze
|
|
540
|
-
- `defaultMessage` (string, optional) - Default message if error message cannot be extracted (default: 'An error occurred')
|
|
541
|
-
- Returns: `CustomError` instance with extracted status code, message, and data
|
|
542
|
-
|
|
543
|
-
- **`httpHelper.format(str, ...args)`** - Format a string with placeholders
|
|
544
|
-
- `str` (string) - String with `{0}`, `{1}`, etc. placeholders
|
|
545
|
-
- `...args` - Values to replace placeholders
|
|
546
|
-
- Returns: Formatted string
|
|
547
|
-
|
|
548
|
-
- **`httpHelper.toZodMessage(error)`** - Generate friendly Zod validation error message
|
|
549
|
-
- `error` (ZodError) - Zod validation error
|
|
550
|
-
- Returns: Formatted error message string
|
|
551
|
-
|
|
552
|
-
---
|
|
106
|
+
[📖 Full HTTP Handlers Documentation](./docs/http-handlers.md)
|
|
553
107
|
|
|
554
108
|
## Features
|
|
555
109
|
|
|
556
|
-
- ✅ **
|
|
557
|
-
- ✅ **JWT
|
|
558
|
-
- ✅ **Flexible Routing** - Easy mounting
|
|
559
|
-
- ✅ **Redis
|
|
560
|
-
- ✅ **Error Handling** - Standardized
|
|
561
|
-
- ✅ **TypeScript
|
|
562
|
-
- ✅ **
|
|
563
|
-
- ✅ **Automatic Reconnection** - Redis auto-reconnect with event handling
|
|
110
|
+
- ✅ **SSO Integration** - Full SSO support with Redis or memory storage
|
|
111
|
+
- ✅ **JWT Security** - Encrypted JWT tokens using JWE (jose library)
|
|
112
|
+
- ✅ **Flexible Routing** - Easy mounting with context paths and middleware
|
|
113
|
+
- ✅ **Redis Support** - TLS/SSL and automatic reconnection
|
|
114
|
+
- ✅ **Error Handling** - Standardized HTTP responses
|
|
115
|
+
- ✅ **TypeScript** - Complete type definitions included
|
|
116
|
+
- ✅ **Production Ready** - Session locking, auto-reconnection, error handling
|
|
564
117
|
|
|
565
118
|
## Requirements
|
|
566
119
|
|
|
@@ -568,26 +121,31 @@ The `httpHelper` object provides utility methods for error handling:
|
|
|
568
121
|
- Express.js >= 4.x
|
|
569
122
|
- Redis (optional, for session storage)
|
|
570
123
|
|
|
571
|
-
## TypeScript
|
|
124
|
+
## TypeScript Support
|
|
572
125
|
|
|
573
|
-
This package includes TypeScript definitions
|
|
126
|
+
This package includes TypeScript definitions:
|
|
574
127
|
|
|
575
128
|
```typescript
|
|
576
129
|
import type {
|
|
577
|
-
SessionConfig,
|
|
578
130
|
SessionManager,
|
|
579
|
-
|
|
580
|
-
SessionUserAttributes,
|
|
131
|
+
SessionConfig,
|
|
581
132
|
JwtManager,
|
|
582
|
-
JwtManagerOptions,
|
|
583
|
-
JwtEncryptOptions,
|
|
584
|
-
JwtDecryptOptions,
|
|
585
133
|
FlexRouter,
|
|
586
134
|
RedisManager,
|
|
587
135
|
CustomError
|
|
588
136
|
} from '@igxjs/node-components';
|
|
589
137
|
```
|
|
590
138
|
|
|
139
|
+
## Documentation
|
|
140
|
+
|
|
141
|
+
📚 **[Complete Documentation](./docs/README.md)** - Detailed guides for all components
|
|
142
|
+
|
|
143
|
+
- [SessionManager Documentation](./docs/session-manager.md) - Comprehensive SSO session management guide
|
|
144
|
+
- [FlexRouter Documentation](./docs/flex-router.md) - Advanced routing patterns
|
|
145
|
+
- [RedisManager Documentation](./docs/redis-manager.md) - Redis connection management
|
|
146
|
+
- [JWT Manager Documentation](./docs/jwt-manager.md) - Token authentication guide
|
|
147
|
+
- [HTTP Handlers Documentation](./docs/http-handlers.md) - Error handling utilities
|
|
148
|
+
|
|
591
149
|
## License
|
|
592
150
|
|
|
593
|
-
[Apache 2.0](LICENSE
|
|
151
|
+
[Apache 2.0](LICENSE)
|