@igxjs/node-components 1.0.8 → 1.0.10
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/http-handlers.js +6 -0
- package/components/jwt.js +89 -45
- package/components/session.js +36 -18
- package/index.d.ts +64 -40
- package/package.json +10 -3
- package/.github/workflows/node.js.yml +0 -31
- package/.github/workflows/npm-publish.yml +0 -33
- package/docs/README.md +0 -54
- package/docs/flex-router.md +0 -167
- package/docs/http-handlers.md +0 -302
- package/docs/jwt-manager.md +0 -124
- package/docs/redis-manager.md +0 -210
- package/docs/session-manager.md +0 -160
- package/tests/http-handlers.test.js +0 -21
- package/tests/jwt.test.js +0 -345
- package/tests/redis.test.js +0 -50
- package/tests/router.test.js +0 -50
- package/tests/session.test.js +0 -116
package/docs/redis-manager.md
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
# RedisManager
|
|
2
|
-
|
|
3
|
-
Redis connection management with TLS support and automatic reconnection handling.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
RedisManager provides a robust Redis client with:
|
|
8
|
-
- TLS/SSL support for secure connections
|
|
9
|
-
- Automatic reconnection handling
|
|
10
|
-
- Connection status monitoring
|
|
11
|
-
- Clean disconnection management
|
|
12
|
-
|
|
13
|
-
**Note:** RedisManager is used internally by the [SessionManager](./session-manager.md), so you typically don't need to use it directly unless you need custom Redis operations.
|
|
14
|
-
|
|
15
|
-
## Usage Example
|
|
16
|
-
|
|
17
|
-
```javascript
|
|
18
|
-
import { RedisManager } from '@igxjs/node-components';
|
|
19
|
-
|
|
20
|
-
const redisManager = new RedisManager();
|
|
21
|
-
|
|
22
|
-
// Connect to Redis (with optional TLS certificate)
|
|
23
|
-
const connected = await redisManager.connect(
|
|
24
|
-
'rediss://localhost:6379',
|
|
25
|
-
'/path/to/cert.pem'
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
if (connected) {
|
|
29
|
-
// Get Redis client for direct operations
|
|
30
|
-
const client = redisManager.getClient();
|
|
31
|
-
await client.set('key', 'value');
|
|
32
|
-
const value = await client.get('key');
|
|
33
|
-
console.log(value); // 'value'
|
|
34
|
-
|
|
35
|
-
// Check connection status
|
|
36
|
-
const isConnected = await redisManager.isConnected();
|
|
37
|
-
console.log('Connected:', isConnected);
|
|
38
|
-
|
|
39
|
-
// Disconnect when done
|
|
40
|
-
await redisManager.disConnect();
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Connection URLs
|
|
45
|
-
|
|
46
|
-
RedisManager supports two URL formats:
|
|
47
|
-
|
|
48
|
-
### Standard Redis (non-TLS)
|
|
49
|
-
```javascript
|
|
50
|
-
await redisManager.connect('redis://localhost:6379');
|
|
51
|
-
await redisManager.connect('redis://username:password@host:6379');
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### Secure Redis (TLS)
|
|
55
|
-
```javascript
|
|
56
|
-
// Requires certificate path for TLS
|
|
57
|
-
await redisManager.connect(
|
|
58
|
-
'rediss://localhost:6379',
|
|
59
|
-
'/path/to/certificate.pem'
|
|
60
|
-
);
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Advanced Usage
|
|
64
|
-
|
|
65
|
-
### Custom Operations
|
|
66
|
-
|
|
67
|
-
```javascript
|
|
68
|
-
import { RedisManager } from '@igxjs/node-components';
|
|
69
|
-
|
|
70
|
-
const redisManager = new RedisManager();
|
|
71
|
-
await redisManager.connect(process.env.REDIS_URL);
|
|
72
|
-
|
|
73
|
-
const client = redisManager.getClient();
|
|
74
|
-
|
|
75
|
-
// String operations
|
|
76
|
-
await client.set('user:1', JSON.stringify({ name: 'John' }));
|
|
77
|
-
const user = JSON.parse(await client.get('user:1'));
|
|
78
|
-
|
|
79
|
-
// Hash operations
|
|
80
|
-
await client.hSet('user:2', 'name', 'Jane');
|
|
81
|
-
await client.hSet('user:2', 'email', 'jane@example.com');
|
|
82
|
-
const userData = await client.hGetAll('user:2');
|
|
83
|
-
|
|
84
|
-
// List operations
|
|
85
|
-
await client.lPush('tasks', 'task1');
|
|
86
|
-
await client.lPush('tasks', 'task2');
|
|
87
|
-
const tasks = await client.lRange('tasks', 0, -1);
|
|
88
|
-
|
|
89
|
-
// Set operations
|
|
90
|
-
await client.sAdd('tags', 'javascript');
|
|
91
|
-
await client.sAdd('tags', 'nodejs');
|
|
92
|
-
const tags = await client.sMembers('tags');
|
|
93
|
-
|
|
94
|
-
// Expiration
|
|
95
|
-
await client.setEx('temporary', 3600, 'expires in 1 hour');
|
|
96
|
-
await client.expire('user:1', 3600);
|
|
97
|
-
|
|
98
|
-
// Clean up
|
|
99
|
-
await redisManager.disConnect();
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Connection Monitoring
|
|
103
|
-
|
|
104
|
-
```javascript
|
|
105
|
-
const redisManager = new RedisManager();
|
|
106
|
-
|
|
107
|
-
// Check if connected before operations
|
|
108
|
-
if (await redisManager.isConnected()) {
|
|
109
|
-
const client = redisManager.getClient();
|
|
110
|
-
// Perform operations
|
|
111
|
-
} else {
|
|
112
|
-
console.log('Redis not connected');
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### Error Handling
|
|
117
|
-
|
|
118
|
-
```javascript
|
|
119
|
-
const redisManager = new RedisManager();
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
const connected = await redisManager.connect(process.env.REDIS_URL);
|
|
123
|
-
|
|
124
|
-
if (!connected) {
|
|
125
|
-
console.error('Failed to connect to Redis');
|
|
126
|
-
// Fall back to memory storage or handle appropriately
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const client = redisManager.getClient();
|
|
131
|
-
await client.set('key', 'value');
|
|
132
|
-
|
|
133
|
-
} catch (error) {
|
|
134
|
-
console.error('Redis operation failed:', error);
|
|
135
|
-
} finally {
|
|
136
|
-
await redisManager.disConnect();
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## API Methods
|
|
141
|
-
|
|
142
|
-
### `connect(redisUrl, certPath?)`
|
|
143
|
-
|
|
144
|
-
Connect to Redis server.
|
|
145
|
-
|
|
146
|
-
**Parameters:**
|
|
147
|
-
- `redisUrl` (string) - Redis connection URL (`redis://` or `rediss://`)
|
|
148
|
-
- `certPath` (string, optional) - Path to TLS certificate file (required for `rediss://`)
|
|
149
|
-
|
|
150
|
-
**Returns:** `Promise<boolean>` - Returns `true` if connected successfully
|
|
151
|
-
|
|
152
|
-
**Example:**
|
|
153
|
-
```javascript
|
|
154
|
-
// Non-TLS connection
|
|
155
|
-
await redisManager.connect('redis://localhost:6379');
|
|
156
|
-
|
|
157
|
-
// TLS connection
|
|
158
|
-
await redisManager.connect('rediss://localhost:6379', '/path/to/cert.pem');
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### `getClient()`
|
|
162
|
-
|
|
163
|
-
Get the Redis client instance for direct operations.
|
|
164
|
-
|
|
165
|
-
**Returns:** Redis client object
|
|
166
|
-
|
|
167
|
-
**Example:**
|
|
168
|
-
```javascript
|
|
169
|
-
const client = redisManager.getClient();
|
|
170
|
-
await client.set('key', 'value');
|
|
171
|
-
await client.get('key');
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### `isConnected()`
|
|
175
|
-
|
|
176
|
-
Check if Redis connection is active and responsive.
|
|
177
|
-
|
|
178
|
-
**Returns:** `Promise<boolean>` - Returns `true` if connected and responsive
|
|
179
|
-
|
|
180
|
-
**Example:**
|
|
181
|
-
```javascript
|
|
182
|
-
const connected = await redisManager.isConnected();
|
|
183
|
-
if (connected) {
|
|
184
|
-
// Proceed with operations
|
|
185
|
-
}
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### `disConnect()`
|
|
189
|
-
|
|
190
|
-
Disconnect from Redis server and clean up resources.
|
|
191
|
-
|
|
192
|
-
**Returns:** `Promise<void>`
|
|
193
|
-
|
|
194
|
-
**Example:**
|
|
195
|
-
```javascript
|
|
196
|
-
await redisManager.disConnect();
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
## Features
|
|
200
|
-
|
|
201
|
-
- **Automatic Reconnection**: Handles connection drops and reconnects automatically
|
|
202
|
-
- **TLS Support**: Secure connections with certificate-based authentication
|
|
203
|
-
- **Connection Pooling**: Efficient connection management
|
|
204
|
-
- **Error Handling**: Graceful error handling and logging
|
|
205
|
-
- **Health Checks**: Built-in connection status monitoring
|
|
206
|
-
|
|
207
|
-
## Related Documentation
|
|
208
|
-
|
|
209
|
-
- [SessionManager](./session-manager.md) - Uses RedisManager for session storage
|
|
210
|
-
- [Back to main documentation](../README.md)
|
package/docs/session-manager.md
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
# SessionManager
|
|
2
|
-
|
|
3
|
-
Provides SSO (Single Sign-On) session management with support for Redis and memory-based session stores.
|
|
4
|
-
|
|
5
|
-
## Configuration Options
|
|
6
|
-
|
|
7
|
-
```javascript
|
|
8
|
-
// Example configuration object
|
|
9
|
-
// All fields are strings except SESSION_AGE which is a number
|
|
10
|
-
|
|
11
|
-
const config = {
|
|
12
|
-
// SSO Configuration
|
|
13
|
-
SSO_ENDPOINT_URL: 'https://sso.example.com',
|
|
14
|
-
SSO_CLIENT_ID: 'your-client-id',
|
|
15
|
-
SSO_CLIENT_SECRET: 'your-client-secret',
|
|
16
|
-
SSO_SUCCESS_URL: '/dashboard',
|
|
17
|
-
SSO_FAILURE_URL: '/login',
|
|
18
|
-
|
|
19
|
-
// Session Configuration
|
|
20
|
-
SESSION_AGE: 64800000, // 18 hours in milliseconds
|
|
21
|
-
SESSION_COOKIE_PATH: '/',
|
|
22
|
-
SESSION_SECRET: 'your-session-secret',
|
|
23
|
-
SESSION_PREFIX: 'ibmid:', // Default value when not provided
|
|
24
|
-
|
|
25
|
-
// Redis Configuration (optional - uses memory store if not provided)
|
|
26
|
-
REDIS_URL: 'redis://localhost:6379',
|
|
27
|
-
REDIS_CERT_PATH: '/path/to/cert.pem' // For TLS connections
|
|
28
|
-
};
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## ⚠️ Important: Singleton Pattern
|
|
32
|
-
|
|
33
|
-
**SessionManager should be instantiated once and exported as a singleton.**
|
|
34
|
-
|
|
35
|
-
**Why?**
|
|
36
|
-
- SessionManager manages Redis connections (if configured)
|
|
37
|
-
- Multiple instances can lead to connection pool exhaustion
|
|
38
|
-
- Session state consistency requires a single source of truth
|
|
39
|
-
- Middleware functions need to reference the same instance
|
|
40
|
-
|
|
41
|
-
**✅ Recommended:** Create a separate module that exports a single SessionManager instance
|
|
42
|
-
**❌ Avoid:** Creating new SessionManager instances in multiple files
|
|
43
|
-
|
|
44
|
-
## Recommended File Structure
|
|
45
|
-
|
|
46
|
-
```
|
|
47
|
-
your-project/
|
|
48
|
-
├── src/
|
|
49
|
-
│ ├── config/
|
|
50
|
-
│ │ └── session-manager.js ← Create SessionManager singleton here
|
|
51
|
-
│ ├── routes/
|
|
52
|
-
│ │ └── auth.js ← Import session from config
|
|
53
|
-
│ └── app.js ← Import and setup session
|
|
54
|
-
└── package.json
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## Usage Example
|
|
58
|
-
|
|
59
|
-
### Step 1: Create SessionManager Singleton
|
|
60
|
-
|
|
61
|
-
Create a dedicated file for your SessionManager instance:
|
|
62
|
-
|
|
63
|
-
```javascript
|
|
64
|
-
// config/session-manager.js
|
|
65
|
-
import { SessionManager } from '@igxjs/node-components';
|
|
66
|
-
|
|
67
|
-
// Create and export a single SessionManager instance
|
|
68
|
-
export const session = new SessionManager({
|
|
69
|
-
SSO_ENDPOINT_URL: process.env.SSO_ENDPOINT_URL,
|
|
70
|
-
SSO_CLIENT_ID: process.env.SSO_CLIENT_ID,
|
|
71
|
-
SSO_CLIENT_SECRET: process.env.SSO_CLIENT_SECRET,
|
|
72
|
-
SSO_SUCCESS_URL: '/dashboard',
|
|
73
|
-
SSO_FAILURE_URL: '/login',
|
|
74
|
-
SESSION_AGE: 64800000, // 18 hours in milliseconds
|
|
75
|
-
SESSION_COOKIE_PATH: '/',
|
|
76
|
-
SESSION_SECRET: process.env.SESSION_SECRET,
|
|
77
|
-
SESSION_PREFIX: 'ibmid:',
|
|
78
|
-
REDIS_URL: process.env.REDIS_URL,
|
|
79
|
-
REDIS_CERT_PATH: process.env.REDIS_CERT_PATH
|
|
80
|
-
});
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Step 2: Setup and Use in Your Application
|
|
84
|
-
|
|
85
|
-
Import and use the singleton instance throughout your application:
|
|
86
|
-
|
|
87
|
-
```javascript
|
|
88
|
-
// app.js or index.js
|
|
89
|
-
import express from 'express';
|
|
90
|
-
import { session } from './config/session-manager.js';
|
|
91
|
-
|
|
92
|
-
const app = express();
|
|
93
|
-
|
|
94
|
-
// Initialize session middleware (call once during app startup)
|
|
95
|
-
await session.setup(app, (user) => {
|
|
96
|
-
// Process user object - compute permissions, avatar URL, etc.
|
|
97
|
-
return {
|
|
98
|
-
...user,
|
|
99
|
-
displayName: user.email?.split('@')[0],
|
|
100
|
-
hasAdminAccess: user.authorized && user.email?.endsWith('@admin.com')
|
|
101
|
-
};
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// Use session instance in your routes
|
|
105
|
-
app.get('/protected', session.authenticate(), (req, res) => {
|
|
106
|
-
res.json({ user: req.user });
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
app.get('/auth/callback', session.callback((user) => {
|
|
110
|
-
return {
|
|
111
|
-
...user,
|
|
112
|
-
loginTime: new Date()
|
|
113
|
-
};
|
|
114
|
-
}));
|
|
115
|
-
|
|
116
|
-
app.get('/auth/providers', session.identityProviders());
|
|
117
|
-
app.post('/auth/refresh', session.refresh((user) => {
|
|
118
|
-
return { ...user, refreshedAt: new Date() };
|
|
119
|
-
}));
|
|
120
|
-
app.get('/auth/logout', session.logout());
|
|
121
|
-
|
|
122
|
-
app.listen(3000, () => {
|
|
123
|
-
console.log('Server running on port 3000');
|
|
124
|
-
});
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### Step 3: Import in Other Files
|
|
128
|
-
|
|
129
|
-
```javascript
|
|
130
|
-
// routes/auth.js
|
|
131
|
-
import { Router } from 'express';
|
|
132
|
-
import { session } from '../config/session-manager.js';
|
|
133
|
-
|
|
134
|
-
const router = Router();
|
|
135
|
-
|
|
136
|
-
// Reuse the same session instance
|
|
137
|
-
router.get('/profile', session.authenticate(), (req, res) => {
|
|
138
|
-
res.json({ profile: req.user });
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
export default router;
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## API Methods
|
|
145
|
-
|
|
146
|
-
- **`setup(app, updateUser)`** - Initialize session configurations
|
|
147
|
-
- **`authenticate(isDebugging?, redirectUrl?)`** - Resource protection middleware
|
|
148
|
-
- **`callback(initUser)`** - SSO callback handler for successful login
|
|
149
|
-
- **`identityProviders()`** - Get available identity providers
|
|
150
|
-
- **`logout()`** - Application logout handler (not SSO logout)
|
|
151
|
-
- **`refresh(initUser)`** - Refresh user session with new token
|
|
152
|
-
- **`redisManager()`** - Get the RedisManager instance (returns RedisManager or null)
|
|
153
|
-
- **`hasLock(email)`** - Check if email has a session refresh lock
|
|
154
|
-
- **`lock(email)`** - Lock email for session refresh (prevents concurrent refreshes)
|
|
155
|
-
- **`clearLocks()`** - Clear expired session refresh locks
|
|
156
|
-
|
|
157
|
-
## Related Documentation
|
|
158
|
-
|
|
159
|
-
- [RedisManager](./redis-manager.md) - Used internally by SessionManager for Redis storage
|
|
160
|
-
- [Back to main documentation](../README.md)
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'mocha';
|
|
2
|
-
import { expect } from 'chai';
|
|
3
|
-
import { httpCodes, httpMessages, CustomError } from '../components/http-handlers.js';
|
|
4
|
-
|
|
5
|
-
describe('HTTP Handlers', () => {
|
|
6
|
-
describe('httpCodes', () => {
|
|
7
|
-
it('should have correct HTTP status codes', () => {
|
|
8
|
-
expect(httpCodes.OK).to.equal(200);
|
|
9
|
-
expect(httpCodes.BAD_REQUEST).to.equal(400);
|
|
10
|
-
expect(httpCodes.NOT_FOUND).to.equal(404);
|
|
11
|
-
});
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
describe('CustomError', () => {
|
|
15
|
-
it('should create a CustomError', () => {
|
|
16
|
-
const error = new CustomError(404, 'Not found');
|
|
17
|
-
expect(error.code).to.equal(404);
|
|
18
|
-
expect(error.message).to.equal('Not found');
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
});
|