@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/components/jwt.js CHANGED
@@ -27,7 +27,7 @@ export class JwtManager {
27
27
  /**
28
28
  * Generate JWT token for user session
29
29
  * @param {import('jose').JWTPayload} data User data payload
30
- * @param {string} input Secret key or password for encryption
30
+ * @param {string} secret Secret key or password for encryption
31
31
  * @param {Object} [options] Per-call configuration overrides
32
32
  * @param {string} [options.algorithm] Override default algorithm
33
33
  * @param {string} [options.encryption] Override default encryption method
@@ -38,7 +38,7 @@ export class JwtManager {
38
38
  * @param {string} [options.subject] Override default subject claim
39
39
  * @returns {Promise<string>} Returns encrypted JWT token
40
40
  */
41
- async encrypt(data, input, options = {}) {
41
+ async encrypt(data, secret, options = {}) {
42
42
  const algorithm = options.algorithm || this.algorithm;
43
43
  const encryption = options.encryption || this.encryption;
44
44
  const expirationTime = options.expirationTime || this.expirationTime;
@@ -47,9 +47,9 @@ export class JwtManager {
47
47
  const audience = options.audience || this.audience;
48
48
  const subject = options.subject || this.subject;
49
49
 
50
- const secret = await crypto.subtle.digest(
50
+ const secretHash = await crypto.subtle.digest(
51
51
  secretHashAlgorithm,
52
- new TextEncoder().encode(input)
52
+ new TextEncoder().encode(secret)
53
53
  );
54
54
 
55
55
  const jwt = new EncryptJWT(data)
@@ -65,13 +65,13 @@ export class JwtManager {
65
65
  if (audience) jwt.setAudience(audience);
66
66
  if (subject) jwt.setSubject(subject);
67
67
 
68
- return await jwt.encrypt(new Uint8Array(secret));
68
+ return await jwt.encrypt(new Uint8Array(secretHash));
69
69
  }
70
70
 
71
71
  /**
72
72
  * Decrypt JWT token for user session
73
73
  * @param {string} token JWT token to decrypt
74
- * @param {string} input Secret key or password for decryption
74
+ * @param {string} secret Secret key or password for decryption
75
75
  * @param {Object} [options] Per-call configuration overrides
76
76
  * @param {number} [options.clockTolerance] Override default clock tolerance
77
77
  * @param {string} [options.secretHashAlgorithm] Override default hash algorithm
@@ -80,16 +80,16 @@ export class JwtManager {
80
80
  * @param {string} [options.subject] Expected subject claim for validation
81
81
  * @returns {Promise<import('jose').JWTDecryptResult<import('jose').EncryptJWT>>} Returns decrypted JWT token
82
82
  */
83
- async decrypt(token, input, options = {}) {
83
+ async decrypt(token, secret, options = {}) {
84
84
  const clockTolerance = options.clockTolerance ?? this.clockTolerance;
85
85
  const secretHashAlgorithm = options.secretHashAlgorithm || this.secretHashAlgorithm;
86
86
  const issuer = options.issuer || this.issuer;
87
87
  const audience = options.audience || this.audience;
88
88
  const subject = options.subject || this.subject;
89
89
 
90
- const secret = await crypto.subtle.digest(
90
+ const secretHash = await crypto.subtle.digest(
91
91
  secretHashAlgorithm,
92
- new TextEncoder().encode(input)
92
+ new TextEncoder().encode(secret)
93
93
  );
94
94
 
95
95
  const decryptOptions = { clockTolerance };
@@ -99,6 +99,6 @@ export class JwtManager {
99
99
  if (audience) decryptOptions.audience = audience;
100
100
  if (subject) decryptOptions.subject = subject;
101
101
 
102
- return await jwtDecrypt(token, new Uint8Array(secret), decryptOptions);
102
+ return await jwtDecrypt(token, new Uint8Array(secretHash), decryptOptions);
103
103
  }
104
104
  }
package/docs/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # Node Components Documentation
2
+
3
+ Detailed documentation for `@igxjs/node-components` - shared components for Express.js applications.
4
+
5
+ ## 📚 Component Documentation
6
+
7
+ ### Core Modules
8
+
9
+ - **[SessionManager](./session-manager.md)** - SSO session management with Redis and memory storage
10
+ - Configuration options and singleton pattern
11
+ - Complete setup and usage examples
12
+ - API reference for all methods
13
+
14
+ - **[FlexRouter](./flex-router.md)** - Flexible routing utility for Express.js
15
+ - Context path and middleware management
16
+ - API versioning and route organization
17
+ - Advanced usage patterns
18
+
19
+ - **[RedisManager](./redis-manager.md)** - Redis connection management
20
+ - TLS/SSL support
21
+ - Connection monitoring and error handling
22
+ - Direct Redis operations
23
+
24
+ - **[JWT Manager](./jwt-manager.md)** - JWT encryption and decryption
25
+ - Secure token-based authentication
26
+ - Express.js integration patterns
27
+ - Refresh token implementation
28
+
29
+ - **[HTTP Handlers](./http-handlers.md)** - Standardized error handling
30
+ - Custom error classes and middleware
31
+ - HTTP status codes and messages
32
+ - Axios error handling and validation helpers
33
+
34
+ ## 🚀 Quick Links
35
+
36
+ - [Main README](../README.md) - Package overview and installation
37
+ - [GitHub Repository](https://github.com/igxjs/node-components)
38
+
39
+ ## 💡 Getting Help
40
+
41
+ If you need help:
42
+ 1. Check the relevant component documentation above
43
+ 2. Review the examples in each guide
44
+ 3. Look at the type definitions in `index.d.ts`
45
+ 4. Open an issue on GitHub
46
+
47
+ ## 📖 Documentation Structure
48
+
49
+ Each component documentation includes:
50
+ - Overview of features
51
+ - Configuration options
52
+ - Basic and advanced usage examples
53
+ - Complete API reference
54
+ - Related documentation links
@@ -0,0 +1,167 @@
1
+ # FlexRouter
2
+
3
+ A flexible routing utility for Express.js that allows mounting routers with custom context paths and middleware handlers.
4
+
5
+ ## Overview
6
+
7
+ FlexRouter provides a convenient way to organize and mount Express routers with predefined context paths and optional middleware. This is particularly useful for:
8
+ - API versioning (e.g., `/api/v1`, `/api/v2`)
9
+ - Separating public and protected routes
10
+ - Applying middleware to specific route groups
11
+ - Managing complex routing hierarchies
12
+
13
+ ## Usage Example
14
+
15
+ ```javascript
16
+ import { Router } from 'express';
17
+ import { FlexRouter } from '@igxjs/node-components';
18
+ // Assuming you have an authenticate middleware
19
+ // import { authenticate } from './middlewares/auth.js';
20
+
21
+ // Create routers
22
+ const publicRouter = Router();
23
+ const privateRouter = Router();
24
+
25
+ publicRouter.get('/health', (req, res) => {
26
+ res.send('OK');
27
+ });
28
+
29
+ privateRouter.get('/users', (req, res) => {
30
+ res.json({ users: [] });
31
+ });
32
+
33
+ // Define flex routers with context paths and optional middleware
34
+ export const routers = [
35
+ new FlexRouter('/api/v1/public', publicRouter),
36
+ new FlexRouter('/api/v1/protected', privateRouter, [authenticate]), // with middleware
37
+ ];
38
+
39
+ // Mount all routers to your Express app
40
+ const app = express();
41
+ const basePath = '';
42
+
43
+ routers.forEach(router => {
44
+ router.mount(app, basePath);
45
+ });
46
+
47
+ // Routes will be available at:
48
+ // - /api/v1/public/health
49
+ // - /api/v1/protected/users (with authenticate middleware)
50
+ ```
51
+
52
+ ## Advanced Usage
53
+
54
+ ### Multiple Middleware
55
+
56
+ You can apply multiple middleware functions to a FlexRouter:
57
+
58
+ ```javascript
59
+ import { rateLimiter } from './middlewares/rate-limiter.js';
60
+ import { logger } from './middlewares/logger.js';
61
+ import { authenticate } from './middlewares/auth.js';
62
+
63
+ const apiRouter = Router();
64
+
65
+ apiRouter.get('/data', (req, res) => {
66
+ res.json({ [] });
67
+ });
68
+
69
+ // Apply multiple middleware in order
70
+ const protectedApi = new FlexRouter(
71
+ '/api/v1',
72
+ apiRouter,
73
+ [logger, rateLimiter, authenticate] // Applied in this order
74
+ );
75
+
76
+ protectedApi.mount(app, '');
77
+ ```
78
+
79
+ ### Using Base Paths
80
+
81
+ You can add a base path when mounting routers, useful for multi-tenant applications:
82
+
83
+ ```javascript
84
+ const tenantRouter = Router();
85
+
86
+ tenantRouter.get('/dashboard', (req, res) => {
87
+ res.json({ tenant: req.params.tenantId });
88
+ });
89
+
90
+ const flexRouter = new FlexRouter('/api', tenantRouter);
91
+
92
+ // Mount with tenant-specific base path
93
+ flexRouter.mount(app, '/tenant/:tenantId');
94
+
95
+ // Route will be available at: /tenant/:tenantId/api/dashboard
96
+ ```
97
+
98
+ ### Organizing Routes by Feature
99
+
100
+ ```javascript
101
+ // features/users/routes.js
102
+ const usersRouter = Router();
103
+ usersRouter.get('/', getAllUsers);
104
+ usersRouter.post('/', createUser);
105
+ export const usersFlexRouter = new FlexRouter('/users', usersRouter);
106
+
107
+ // features/products/routes.js
108
+ const productsRouter = Router();
109
+ productsRouter.get('/', getAllProducts);
110
+ export const productsFlexRouter = new FlexRouter('/products', productsRouter);
111
+
112
+ // app.js
113
+ import { usersFlexRouter } from './features/users/routes.js';
114
+ import { productsFlexRouter } from './features/products/routes.js';
115
+
116
+ const apiRouters = [usersFlexRouter, productsFlexRouter];
117
+
118
+ apiRouters.forEach(router => router.mount(app, '/api/v1'));
119
+
120
+ // Routes available:
121
+ // - /api/v1/users
122
+ // - /api/v1/products
123
+ ```
124
+
125
+ ## API
126
+
127
+ ### Constructor
128
+
129
+ **`new FlexRouter(context, router, handlers?)`**
130
+
131
+ Creates a new FlexRouter instance.
132
+
133
+ **Parameters:**
134
+ - `context` (string) - The context path for the router (e.g., `/api/v1`)
135
+ - `router` (Router) - Express Router instance containing your route definitions
136
+ - `handlers` (Array, optional) - Array of middleware handler functions to apply to all routes in this router
137
+
138
+ **Returns:** FlexRouter instance
139
+
140
+ ### Methods
141
+
142
+ **`mount(app, basePath)`**
143
+
144
+ Mounts the router to an Express application with the specified base path.
145
+
146
+ **Parameters:**
147
+ - `app` (Express) - Express application instance
148
+ - `basePath` (string) - Base path to prepend to the context path
149
+
150
+ **Example:**
151
+ ```javascript
152
+ const flexRouter = new FlexRouter('/api', router);
153
+ flexRouter.mount(app, '/v1'); // Mounts at /v1/api
154
+ ```
155
+
156
+ ## Best Practices
157
+
158
+ 1. **Group Related Routes**: Use FlexRouter to group related routes together
159
+ 2. **Apply Middleware Strategically**: Apply middleware at the FlexRouter level for route groups that share the same requirements
160
+ 3. **Consistent Naming**: Use consistent naming conventions for context paths (e.g., all lowercase, kebab-case)
161
+ 4. **Version Your APIs**: Use FlexRouter to manage different API versions easily
162
+ 5. **Keep Routers Focused**: Each router should handle a specific feature or resource type
163
+
164
+ ## Related Documentation
165
+
166
+ - [SessionManager](./session-manager.md) - For authentication middleware usage
167
+ - [Back to main documentation](../README.md)
@@ -0,0 +1,302 @@
1
+ # HTTP Handlers
2
+
3
+ Custom error handling utilities with standardized HTTP status codes and error responses for Express.js applications.
4
+
5
+ ## Overview
6
+
7
+ The HTTP Handlers module provides:
8
+ - Standardized error handling middleware
9
+ - Custom error classes
10
+ - HTTP status codes and messages constants
11
+ - 404 handler for unmatched routes
12
+ - Utility functions for error formatting
13
+ - Axios error handling helpers
14
+
15
+ ## Available Exports
16
+
17
+ ```javascript
18
+ import {
19
+ httpCodes, // HTTP status code constants
20
+ httpMessages, // HTTP status message constants
21
+ httpErrorHandler, // Error handling middleware
22
+ httpNotFoundHandler, // 404 handler middleware
23
+ CustomError, // Custom error class
24
+ httpHelper, // Utility functions
25
+ httpError // Error factory function
26
+ } from '@igxjs/node-components';
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ```javascript
32
+ import express from 'express';
33
+ import {
34
+ httpCodes,
35
+ httpErrorHandler,
36
+ httpNotFoundHandler,
37
+ httpError
38
+ } from '@igxjs/node-components';
39
+
40
+ const app = express();
41
+
42
+ // Your routes
43
+ app.get('/api/data', async (req, res, next) => {
44
+ try {
45
+ const data = await fetchData();
46
+ res.json(data);
47
+ } catch (error) {
48
+ next(httpError(httpCodes.SYSTEM_FAILURE, 'Failed to fetch data', error));
49
+ }
50
+ });
51
+
52
+ // Add 404 handler before error handler
53
+ app.use(httpNotFoundHandler);
54
+
55
+ // Add error handler as the last middleware
56
+ app.use(httpErrorHandler);
57
+
58
+ app.listen(3000);
59
+ ```
60
+
61
+ ## HTTP Status Codes
62
+
63
+ The `httpCodes` object provides constants for common HTTP status codes:
64
+
65
+ ```javascript
66
+ import { httpCodes } from '@igxjs/node-components';
67
+
68
+ // Success codes
69
+ httpCodes.OK // 200
70
+ httpCodes.CREATED // 201
71
+ httpCodes.NO_CONTENT // 204
72
+
73
+ // Client error codes
74
+ httpCodes.BAD_REQUEST // 400
75
+ httpCodes.UNAUTHORIZED // 401
76
+ httpCodes.FORBIDDEN // 403
77
+ httpCodes.NOT_FOUND // 404
78
+ httpCodes.NOT_ACCEPTABLE // 406
79
+ httpCodes.CONFLICT // 409
80
+ httpCodes.LOCKED // 423
81
+
82
+ // Server error codes
83
+ httpCodes.SYSTEM_FAILURE // 500
84
+ httpCodes.NOT_IMPLEMENTED // 501
85
+ ```
86
+
87
+ ## HTTP Status Messages
88
+
89
+ Corresponding status messages are available via `httpMessages`:
90
+
91
+ ```javascript
92
+ import { httpMessages } from '@igxjs/node-components';
93
+
94
+ httpMessages.OK // 'OK'
95
+ httpMessages.BAD_REQUEST // 'Bad Request'
96
+ httpMessages.UNAUTHORIZED // 'Unauthorized'
97
+ // ... etc.
98
+ ```
99
+
100
+ ## CustomError Class
101
+
102
+ Create custom errors with specific HTTP status codes:
103
+
104
+ ```javascript
105
+ import { CustomError, httpCodes } from '@igxjs/node-components';
106
+
107
+ // Constructor: new CustomError(code, message, error?, data?)
108
+ throw new CustomError(
109
+ httpCodes.BAD_REQUEST,
110
+ 'Email is required',
111
+ null,
112
+ { field: 'email' }
113
+ );
114
+ ```
115
+
116
+ **Properties:**
117
+ - `code` (number) - HTTP status code
118
+ - `message` (string) - Error message
119
+ - `error` (object, optional) - Original error object
120
+ - `data` (object, optional) - Additional error data
121
+
122
+ ## httpError Function
123
+
124
+ Convenience function to create CustomError instances:
125
+
126
+ ```javascript
127
+ import { httpError, httpCodes } from '@igxjs/node-components';
128
+
129
+ // Same as: new CustomError(code, message, error, data)
130
+ throw httpError(
131
+ httpCodes.UNAUTHORIZED,
132
+ 'Invalid credentials',
133
+ originalError,
134
+ { attempted: username }
135
+ );
136
+ ```
137
+
138
+ ## Middleware
139
+
140
+ ### httpErrorHandler
141
+
142
+ Express error handling middleware that processes CustomError and other errors:
143
+
144
+ ```javascript
145
+ import { httpErrorHandler } from '@igxjs/node-components';
146
+
147
+ // Add as the last middleware
148
+ app.use(httpErrorHandler);
149
+ ```
150
+
151
+ **Features:**
152
+ - Automatically handles `CustomError` instances
153
+ - Sets appropriate HTTP status codes
154
+ - Adds CORS headers
155
+ - Logs error details to console
156
+ - Returns standardized JSON error responses
157
+
158
+ **Response Format:**
159
+ ```json
160
+ {
161
+ "error": {
162
+ "code": 400,
163
+ "message": "Email is required",
164
+ "data": { "field": "email" }
165
+ }
166
+ }
167
+ ```
168
+
169
+ ### httpNotFoundHandler
170
+
171
+ Middleware that catches all unmatched routes and returns 404:
172
+
173
+ ```javascript
174
+ import { httpNotFoundHandler } from '@igxjs/node-components';
175
+
176
+ // Add before error handler
177
+ app.use(httpNotFoundHandler);
178
+ app.use(httpErrorHandler);
179
+ ```
180
+
181
+ ## httpHelper Utilities
182
+
183
+ ### `handleAxiosError(error, defaultMessage?)`
184
+
185
+ Analyze and convert Axios/HTTP errors to CustomError:
186
+
187
+ ```javascript
188
+ import axios from 'axios';
189
+ import { httpHelper } from '@igxjs/node-components';
190
+
191
+ try {
192
+ const response = await axios.get('https://api.example.com/data');
193
+ return response.data;
194
+ } catch (error) {
195
+ // Converts Axios error to CustomError with extracted status and message
196
+ throw httpHelper.handleAxiosError(error, 'API request failed');
197
+ }
198
+ ```
199
+
200
+ ### `format(str, ...args)`
201
+
202
+ Format strings with placeholders:
203
+
204
+ ```javascript
205
+ import { httpHelper } from '@igxjs/node-components';
206
+
207
+ const message = httpHelper.format(
208
+ 'User {0} not found in {1}',
209
+ 'john@example.com',
210
+ 'database'
211
+ );
212
+ // Result: 'User john@example.com not found in database'
213
+ ```
214
+
215
+ ### `toZodMessage(error)`
216
+
217
+ Generate friendly Zod validation error messages:
218
+
219
+ ```javascript
220
+ import { z } from 'zod';
221
+ import { httpHelper, httpError, httpCodes } from '@igxjs/node-components';
222
+
223
+ const userSchema = z.object({
224
+ email: z.string().email(),
225
+ age: z.number().min(18)
226
+ });
227
+
228
+ app.post('/api/users', (req, res, next) => {
229
+ try {
230
+ const validated = userSchema.parse(req.body);
231
+ // Process validated data
232
+ } catch (error) {
233
+ if (error instanceof z.ZodError) {
234
+ const message = httpHelper.toZodMessage(error);
235
+ throw httpError(httpCodes.BAD_REQUEST, message, error);
236
+ }
237
+ next(error);
238
+ }
239
+ });
240
+ ```
241
+
242
+ ## Complete Example
243
+
244
+ ```javascript
245
+ import express from 'express';
246
+ import {
247
+ httpCodes,
248
+ httpMessages,
249
+ httpError,
250
+ httpErrorHandler,
251
+ httpNotFoundHandler,
252
+ CustomError
253
+ } from '@igxjs/node-components';
254
+
255
+ const app = express();
256
+ app.use(express.json());
257
+
258
+ // Routes
259
+ app.get('/api/health', (req, res) => {
260
+ res.json({ status: httpMessages.OK });
261
+ });
262
+
263
+ app.post('/api/login', async (req, res, next) => {
264
+ try {
265
+ const { username, password } = req.body;
266
+
267
+ if (!username || !password) {
268
+ throw httpError(
269
+ httpCodes.BAD_REQUEST,
270
+ 'Username and password are required'
271
+ );
272
+ }
273
+
274
+ const user = await authenticate(username, password);
275
+
276
+ if (!user) {
277
+ throw new CustomError(
278
+ httpCodes.UNAUTHORIZED,
279
+ 'Invalid credentials'
280
+ );
281
+ }
282
+
283
+ res.json({ user });
284
+ } catch (error) {
285
+ next(error);
286
+ }
287
+ });
288
+
289
+ // 404 handler
290
+ app.use(httpNotFoundHandler);
291
+
292
+ // Error handler (must be last)
293
+ app.use(httpErrorHandler);
294
+
295
+ app.listen(3000);
296
+ ```
297
+
298
+ ## Related Documentation
299
+
300
+ - [JWT Manager](./jwt-manager.md) - For token-based authentication
301
+ - [SessionManager](./session-manager.md) - For session-based authentication
302
+ - [Back to main documentation](../README.md)