te.js 2.0.3 → 2.1.1

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.
Files changed (68) hide show
  1. package/README.md +197 -187
  2. package/auto-docs/analysis/handler-analyzer.js +58 -58
  3. package/auto-docs/analysis/source-resolver.js +101 -101
  4. package/auto-docs/constants.js +37 -37
  5. package/auto-docs/docs-llm/index.js +7 -0
  6. package/auto-docs/{llm → docs-llm}/prompts.js +222 -222
  7. package/auto-docs/{llm → docs-llm}/provider.js +132 -187
  8. package/auto-docs/index.js +146 -146
  9. package/auto-docs/openapi/endpoint-processor.js +277 -277
  10. package/auto-docs/openapi/generator.js +107 -107
  11. package/auto-docs/openapi/level3.js +131 -131
  12. package/auto-docs/openapi/spec-builders.js +244 -244
  13. package/auto-docs/ui/docs-ui.js +186 -186
  14. package/auto-docs/utils/logger.js +17 -17
  15. package/auto-docs/utils/strip-usage.js +10 -10
  16. package/cli/docs-command.js +315 -315
  17. package/cli/fly-command.js +71 -71
  18. package/cli/index.js +56 -56
  19. package/database/index.js +165 -165
  20. package/database/mongodb.js +146 -146
  21. package/database/redis.js +201 -201
  22. package/docs/README.md +36 -36
  23. package/docs/ammo.md +362 -362
  24. package/docs/api-reference.md +490 -489
  25. package/docs/auto-docs.md +216 -215
  26. package/docs/cli.md +152 -152
  27. package/docs/configuration.md +275 -233
  28. package/docs/database.md +390 -391
  29. package/docs/error-handling.md +438 -417
  30. package/docs/file-uploads.md +333 -334
  31. package/docs/getting-started.md +214 -215
  32. package/docs/middleware.md +355 -356
  33. package/docs/rate-limiting.md +393 -394
  34. package/docs/routing.md +302 -302
  35. package/package.json +62 -62
  36. package/rate-limit/algorithms/fixed-window.js +141 -141
  37. package/rate-limit/algorithms/sliding-window.js +147 -147
  38. package/rate-limit/algorithms/token-bucket.js +115 -115
  39. package/rate-limit/base.js +165 -165
  40. package/rate-limit/index.js +147 -147
  41. package/rate-limit/storage/base.js +104 -104
  42. package/rate-limit/storage/memory.js +101 -101
  43. package/rate-limit/storage/redis.js +88 -88
  44. package/server/ammo/body-parser.js +220 -220
  45. package/server/ammo/dispatch-helper.js +103 -103
  46. package/server/ammo/enhancer.js +57 -57
  47. package/server/ammo.js +454 -356
  48. package/server/endpoint.js +97 -74
  49. package/server/error.js +9 -9
  50. package/server/errors/code-context.js +125 -0
  51. package/server/errors/llm-error-service.js +140 -0
  52. package/server/files/helper.js +33 -33
  53. package/server/files/uploader.js +143 -143
  54. package/server/handler.js +158 -113
  55. package/server/target.js +185 -175
  56. package/server/targets/middleware-validator.js +22 -22
  57. package/server/targets/path-validator.js +21 -21
  58. package/server/targets/registry.js +160 -160
  59. package/server/targets/shoot-validator.js +21 -21
  60. package/te.js +428 -363
  61. package/utils/auto-register.js +17 -17
  62. package/utils/configuration.js +64 -64
  63. package/utils/errors-llm-config.js +84 -0
  64. package/utils/request-logger.js +43 -43
  65. package/utils/status-codes.js +82 -82
  66. package/utils/tejas-entrypoint-html.js +18 -18
  67. package/auto-docs/llm/index.js +0 -6
  68. package/auto-docs/llm/parse.js +0 -88
package/docs/database.md CHANGED
@@ -1,391 +1,390 @@
1
- # Database Integration
2
-
3
- Tejas provides built-in support for **MongoDB** and **Redis** databases through a centralized `DatabaseManager`.
4
-
5
- ## Quick Start
6
-
7
- ### Redis
8
-
9
- ```javascript
10
- import Tejas from 'te.js';
11
-
12
- const app = new Tejas();
13
-
14
- app.takeoff({
15
- withRedis: { url: 'redis://localhost:6379' }
16
- });
17
- ```
18
-
19
- ### MongoDB
20
-
21
- ```javascript
22
- app.takeoff({
23
- withMongo: { uri: 'mongodb://localhost:27017/myapp' }
24
- });
25
- ```
26
-
27
- ### Both Together
28
-
29
- ```javascript
30
- app.takeoff({
31
- withRedis: { url: 'redis://localhost:6379' },
32
- withMongo: { uri: 'mongodb://localhost:27017/myapp' }
33
- });
34
- ```
35
-
36
- > **Auto-install:** Tejas automatically installs the `redis` or `mongoose` npm packages on first use if they are not already in your `node_modules`. No manual `npm install` is required for database drivers.
37
-
38
- ## Redis Configuration
39
-
40
- ### Basic Connection
41
-
42
- ```javascript
43
- app.withRedis({
44
- url: 'redis://localhost:6379'
45
- });
46
- ```
47
-
48
- ### With Authentication
49
-
50
- ```javascript
51
- app.withRedis({
52
- url: 'redis://username:password@hostname:6379'
53
- });
54
-
55
- // Or using socket options
56
- app.withRedis({
57
- socket: {
58
- host: 'localhost',
59
- port: 6379
60
- },
61
- password: 'your-password'
62
- });
63
- ```
64
-
65
- ### TLS Connection
66
-
67
- ```javascript
68
- app.withRedis({
69
- socket: {
70
- host: 'your-redis-host.com',
71
- port: 6379,
72
- tls: true
73
- }
74
- });
75
- ```
76
-
77
- ### Redis Cluster
78
-
79
- ```javascript
80
- app.withRedis({
81
- isCluster: true,
82
- url: 'redis://node1:6379'
83
- });
84
- ```
85
-
86
- ### All Options
87
-
88
- ```javascript
89
- app.withRedis({
90
- url: 'redis://localhost:6379', // Connection URL
91
- isCluster: false, // Use Redis Cluster
92
- socket: {
93
- host: 'localhost',
94
- port: 6379,
95
- tls: false
96
- },
97
- password: 'secret', // Redis password
98
- database: 0, // Database number
99
- // ... any other node-redis options
100
- });
101
- ```
102
-
103
- ## MongoDB Configuration
104
-
105
- ### Basic Connection
106
-
107
- ```javascript
108
- app.withMongo({
109
- uri: 'mongodb://localhost:27017/myapp'
110
- });
111
- ```
112
-
113
- ### With Options
114
-
115
- ```javascript
116
- app.withMongo({
117
- uri: 'mongodb://localhost:27017/myapp',
118
- options: {
119
- maxPoolSize: 10,
120
- serverSelectionTimeoutMS: 5000,
121
- socketTimeoutMS: 45000
122
- }
123
- });
124
- ```
125
-
126
- ### MongoDB Atlas
127
-
128
- ```javascript
129
- app.withMongo({
130
- uri: 'mongodb+srv://username:password@cluster.mongodb.net/myapp'
131
- });
132
- ```
133
-
134
- ### Replica Set
135
-
136
- ```javascript
137
- app.withMongo({
138
- uri: 'mongodb://host1:27017,host2:27017,host3:27017/myapp?replicaSet=myReplicaSet'
139
- });
140
- ```
141
-
142
- ## Using Database Connections
143
-
144
- ### Getting Connections
145
-
146
- Import the database manager to access connections:
147
-
148
- ```javascript
149
- import dbManager from 'te.js/database/index.js';
150
-
151
- // Get Redis client
152
- const redis = dbManager.getConnection('redis');
153
-
154
- // Get MongoDB client
155
- const mongo = dbManager.getConnection('mongodb');
156
- ```
157
-
158
- ### In Route Handlers
159
-
160
- ```javascript
161
- import { Target } from 'te.js';
162
- import dbManager from 'te.js/database/index.js';
163
-
164
- const cache = new Target('/cache');
165
-
166
- cache.register('/get/:key', async (ammo) => {
167
- const redis = dbManager.getConnection('redis');
168
- const { key } = ammo.payload;
169
-
170
- const value = await redis.get(key);
171
-
172
- if (!value) {
173
- return ammo.fire(404, { error: 'Key not found' });
174
- }
175
-
176
- ammo.fire({ key, value });
177
- });
178
-
179
- cache.register('/set', async (ammo) => {
180
- if (!ammo.POST) return ammo.notAllowed();
181
-
182
- const redis = dbManager.getConnection('redis');
183
- const { key, value, ttl } = ammo.payload;
184
-
185
- if (ttl) {
186
- await redis.setEx(key, ttl, value);
187
- } else {
188
- await redis.set(key, value);
189
- }
190
-
191
- ammo.fire(201, { message: 'Cached successfully' });
192
- });
193
- ```
194
-
195
- ### MongoDB Example
196
-
197
- ```javascript
198
- import { Target, TejError } from 'te.js';
199
- import dbManager from 'te.js/database/index.js';
200
-
201
- const users = new Target('/users');
202
-
203
- users.register('/', async (ammo) => {
204
- const mongo = dbManager.getConnection('mongodb');
205
- const db = mongo.db('myapp');
206
- const collection = db.collection('users');
207
-
208
- if (ammo.GET) {
209
- const users = await collection.find({}).toArray();
210
- return ammo.fire(users);
211
- }
212
-
213
- if (ammo.POST) {
214
- const { name, email } = ammo.payload;
215
- const result = await collection.insertOne({ name, email, createdAt: new Date() });
216
- return ammo.fire(201, { id: result.insertedId, name, email });
217
- }
218
-
219
- ammo.notAllowed();
220
- });
221
-
222
- users.register('/:id', async (ammo) => {
223
- const mongo = dbManager.getConnection('mongodb');
224
- const db = mongo.db('myapp');
225
- const collection = db.collection('users');
226
-
227
- const { id } = ammo.payload;
228
- const { ObjectId } = await import('mongodb');
229
-
230
- const user = await collection.findOne({ _id: new ObjectId(id) });
231
-
232
- if (!user) {
233
- throw new TejError(404, 'User not found');
234
- }
235
-
236
- ammo.fire(user);
237
- });
238
- ```
239
-
240
- ## Database Manager API
241
-
242
- Access the database manager directly for advanced usage:
243
-
244
- ```javascript
245
- import dbManager from 'te.js/database/index.js';
246
- ```
247
-
248
- ### Check Connection Status
249
-
250
- ```javascript
251
- const status = dbManager.hasConnection('redis', {});
252
- // Returns: { exists: boolean, initializing: boolean }
253
-
254
- if (status.exists) {
255
- const redis = dbManager.getConnection('redis');
256
- }
257
- ```
258
-
259
- The `initializing` flag is `true` while the connection is being established.
260
-
261
- ### Get All Active Connections
262
-
263
- ```javascript
264
- const connections = dbManager.getActiveConnections();
265
- // Returns a Map: { 'redis' => { type, client, config }, 'mongodb' => { type, client, config } }
266
- ```
267
-
268
- ### Close Connections
269
-
270
- ```javascript
271
- // Close a specific connection
272
- await dbManager.closeConnection('redis');
273
-
274
- // Close all connections
275
- await dbManager.closeAllConnections();
276
- ```
277
-
278
- ## Caching Pattern
279
-
280
- A common pattern using Redis for caching:
281
-
282
- ```javascript
283
- import { Target } from 'te.js';
284
- import dbManager from 'te.js/database/index.js';
285
-
286
- const api = new Target('/api');
287
-
288
- // Cache middleware
289
- const withCache = (ttl = 60) => async (ammo, next) => {
290
- if (!ammo.GET) return next();
291
-
292
- const redis = dbManager.getConnection('redis');
293
- const cacheKey = `cache:${ammo.endpoint}`;
294
-
295
- // Try cache first
296
- const cached = await redis.get(cacheKey);
297
- if (cached) {
298
- ammo.res.setHeader('X-Cache', 'HIT');
299
- return ammo.fire(JSON.parse(cached));
300
- }
301
-
302
- // Store original fire to intercept
303
- const originalFire = ammo.fire.bind(ammo);
304
- ammo.fire = async (...args) => {
305
- const data = args[0];
306
- if (typeof data === 'object') {
307
- await redis.setEx(cacheKey, ttl, JSON.stringify(data));
308
- }
309
- ammo.res.setHeader('X-Cache', 'MISS');
310
- originalFire(...args);
311
- };
312
-
313
- next();
314
- };
315
-
316
- api.register('/expensive-data', withCache(300), async (ammo) => {
317
- // This expensive operation result will be cached for 5 minutes
318
- const data = await expensiveOperation();
319
- ammo.fire(data);
320
- });
321
- ```
322
-
323
- ## Session Storage with Redis
324
-
325
- ```javascript
326
- import { v4 as uuidv4 } from 'uuid';
327
- import dbManager from 'te.js/database/index.js';
328
-
329
- const sessionMiddleware = async (ammo, next) => {
330
- const redis = dbManager.getConnection('redis');
331
- let sessionId = ammo.headers['x-session-id'];
332
-
333
- if (!sessionId) {
334
- sessionId = uuidv4();
335
- ammo.res.setHeader('X-Session-ID', sessionId);
336
- ammo.session = {};
337
- } else {
338
- const sessionData = await redis.get(`session:${sessionId}`);
339
- ammo.session = sessionData ? JSON.parse(sessionData) : {};
340
- }
341
-
342
- // Save session after response
343
- const originalFire = ammo.fire.bind(ammo);
344
- ammo.fire = async (...args) => {
345
- await redis.setEx(
346
- `session:${sessionId}`,
347
- 3600, // 1 hour TTL
348
- JSON.stringify(ammo.session)
349
- );
350
- originalFire(...args);
351
- };
352
-
353
- next();
354
- };
355
- ```
356
-
357
- ## Connection Events
358
-
359
- The underlying clients emit events you can listen to:
360
-
361
- ```javascript
362
- const redis = dbManager.getConnection('redis');
363
-
364
- redis.on('error', (err) => {
365
- console.error('Redis error:', err);
366
- });
367
-
368
- redis.on('connect', () => {
369
- console.log('Redis connected');
370
- });
371
-
372
- redis.on('reconnecting', () => {
373
- console.log('Redis reconnecting...');
374
- });
375
- ```
376
-
377
- ## Best Practices
378
-
379
- 1. **Initialize early** — Set up connections before `takeoff()`
380
- 2. **Handle errors** — Always wrap database operations in try/catch
381
- 3. **Use connection pooling** — MongoDB handles this automatically
382
- 4. **Close on shutdown** — Clean up connections when app terminates
383
-
384
- ```javascript
385
- // Graceful shutdown
386
- process.on('SIGTERM', async () => {
387
- await dbManager.closeAllConnections();
388
- process.exit(0);
389
- });
390
- ```
391
-
1
+ # Database Integration
2
+
3
+ Tejas provides built-in support for **MongoDB** and **Redis** databases through a centralized `DatabaseManager`.
4
+
5
+ ## Quick Start
6
+
7
+ ### Redis
8
+
9
+ ```javascript
10
+ import Tejas from 'te.js';
11
+
12
+ const app = new Tejas();
13
+
14
+ app.takeoff({
15
+ withRedis: { url: 'redis://localhost:6379' }
16
+ });
17
+ ```
18
+
19
+ ### MongoDB
20
+
21
+ ```javascript
22
+ app.takeoff({
23
+ withMongo: { uri: 'mongodb://localhost:27017/myapp' }
24
+ });
25
+ ```
26
+
27
+ ### Both Together
28
+
29
+ ```javascript
30
+ app.takeoff({
31
+ withRedis: { url: 'redis://localhost:6379' },
32
+ withMongo: { uri: 'mongodb://localhost:27017/myapp' }
33
+ });
34
+ ```
35
+
36
+ > **Auto-install:** Tejas automatically installs the `redis` or `mongoose` npm packages on first use if they are not already in your `node_modules`. No manual `npm install` is required for database drivers.
37
+
38
+ ## Redis Configuration
39
+
40
+ ### Basic Connection
41
+
42
+ ```javascript
43
+ app.withRedis({
44
+ url: 'redis://localhost:6379'
45
+ });
46
+ ```
47
+
48
+ ### With Authentication
49
+
50
+ ```javascript
51
+ app.withRedis({
52
+ url: 'redis://username:password@hostname:6379'
53
+ });
54
+
55
+ // Or using socket options
56
+ app.withRedis({
57
+ socket: {
58
+ host: 'localhost',
59
+ port: 6379
60
+ },
61
+ password: 'your-password'
62
+ });
63
+ ```
64
+
65
+ ### TLS Connection
66
+
67
+ ```javascript
68
+ app.withRedis({
69
+ socket: {
70
+ host: 'your-redis-host.com',
71
+ port: 6379,
72
+ tls: true
73
+ }
74
+ });
75
+ ```
76
+
77
+ ### Redis Cluster
78
+
79
+ ```javascript
80
+ app.withRedis({
81
+ isCluster: true,
82
+ url: 'redis://node1:6379'
83
+ });
84
+ ```
85
+
86
+ ### All Options
87
+
88
+ ```javascript
89
+ app.withRedis({
90
+ url: 'redis://localhost:6379', // Connection URL
91
+ isCluster: false, // Use Redis Cluster
92
+ socket: {
93
+ host: 'localhost',
94
+ port: 6379,
95
+ tls: false
96
+ },
97
+ password: 'secret', // Redis password
98
+ database: 0, // Database number
99
+ // ... any other node-redis options
100
+ });
101
+ ```
102
+
103
+ ## MongoDB Configuration
104
+
105
+ ### Basic Connection
106
+
107
+ ```javascript
108
+ app.withMongo({
109
+ uri: 'mongodb://localhost:27017/myapp'
110
+ });
111
+ ```
112
+
113
+ ### With Options
114
+
115
+ ```javascript
116
+ app.withMongo({
117
+ uri: 'mongodb://localhost:27017/myapp',
118
+ options: {
119
+ maxPoolSize: 10,
120
+ serverSelectionTimeoutMS: 5000,
121
+ socketTimeoutMS: 45000
122
+ }
123
+ });
124
+ ```
125
+
126
+ ### MongoDB Atlas
127
+
128
+ ```javascript
129
+ app.withMongo({
130
+ uri: 'mongodb+srv://username:password@cluster.mongodb.net/myapp'
131
+ });
132
+ ```
133
+
134
+ ### Replica Set
135
+
136
+ ```javascript
137
+ app.withMongo({
138
+ uri: 'mongodb://host1:27017,host2:27017,host3:27017/myapp?replicaSet=myReplicaSet'
139
+ });
140
+ ```
141
+
142
+ ## Using Database Connections
143
+
144
+ ### Getting Connections
145
+
146
+ Import the database manager to access connections:
147
+
148
+ ```javascript
149
+ import dbManager from 'te.js/database/index.js';
150
+
151
+ // Get Redis client
152
+ const redis = dbManager.getConnection('redis');
153
+
154
+ // Get MongoDB client
155
+ const mongo = dbManager.getConnection('mongodb');
156
+ ```
157
+
158
+ ### In Route Handlers
159
+
160
+ ```javascript
161
+ import { Target } from 'te.js';
162
+ import dbManager from 'te.js/database/index.js';
163
+
164
+ const cache = new Target('/cache');
165
+
166
+ cache.register('/get/:key', async (ammo) => {
167
+ const redis = dbManager.getConnection('redis');
168
+ const { key } = ammo.payload;
169
+
170
+ const value = await redis.get(key);
171
+
172
+ if (!value) {
173
+ return ammo.fire(404, { error: 'Key not found' });
174
+ }
175
+
176
+ ammo.fire({ key, value });
177
+ });
178
+
179
+ cache.register('/set', async (ammo) => {
180
+ if (!ammo.POST) return ammo.notAllowed();
181
+
182
+ const redis = dbManager.getConnection('redis');
183
+ const { key, value, ttl } = ammo.payload;
184
+
185
+ if (ttl) {
186
+ await redis.setEx(key, ttl, value);
187
+ } else {
188
+ await redis.set(key, value);
189
+ }
190
+
191
+ ammo.fire(201, { message: 'Cached successfully' });
192
+ });
193
+ ```
194
+
195
+ ### MongoDB Example
196
+
197
+ ```javascript
198
+ import { Target, TejError } from 'te.js';
199
+ import dbManager from 'te.js/database/index.js';
200
+
201
+ const users = new Target('/users');
202
+
203
+ users.register('/', async (ammo) => {
204
+ const mongo = dbManager.getConnection('mongodb');
205
+ const db = mongo.db('myapp');
206
+ const collection = db.collection('users');
207
+
208
+ if (ammo.GET) {
209
+ const users = await collection.find({}).toArray();
210
+ return ammo.fire(users);
211
+ }
212
+
213
+ if (ammo.POST) {
214
+ const { name, email } = ammo.payload;
215
+ const result = await collection.insertOne({ name, email, createdAt: new Date() });
216
+ return ammo.fire(201, { id: result.insertedId, name, email });
217
+ }
218
+
219
+ ammo.notAllowed();
220
+ });
221
+
222
+ users.register('/:id', async (ammo) => {
223
+ const mongo = dbManager.getConnection('mongodb');
224
+ const db = mongo.db('myapp');
225
+ const collection = db.collection('users');
226
+
227
+ const { id } = ammo.payload;
228
+ const { ObjectId } = await import('mongodb');
229
+
230
+ const user = await collection.findOne({ _id: new ObjectId(id) });
231
+
232
+ if (!user) {
233
+ throw new TejError(404, 'User not found');
234
+ }
235
+
236
+ ammo.fire(user);
237
+ });
238
+ ```
239
+
240
+ ## Database Manager API
241
+
242
+ Access the database manager directly for advanced usage:
243
+
244
+ ```javascript
245
+ import dbManager from 'te.js/database/index.js';
246
+ ```
247
+
248
+ ### Check Connection Status
249
+
250
+ ```javascript
251
+ const status = dbManager.hasConnection('redis', {});
252
+ // Returns: { exists: boolean, initializing: boolean }
253
+
254
+ if (status.exists) {
255
+ const redis = dbManager.getConnection('redis');
256
+ }
257
+ ```
258
+
259
+ The `initializing` flag is `true` while the connection is being established.
260
+
261
+ ### Get All Active Connections
262
+
263
+ ```javascript
264
+ const connections = dbManager.getActiveConnections();
265
+ // Returns a Map: { 'redis' => { type, client, config }, 'mongodb' => { type, client, config } }
266
+ ```
267
+
268
+ ### Close Connections
269
+
270
+ ```javascript
271
+ // Close a specific connection
272
+ await dbManager.closeConnection('redis');
273
+
274
+ // Close all connections
275
+ await dbManager.closeAllConnections();
276
+ ```
277
+
278
+ ## Caching Pattern
279
+
280
+ A common pattern using Redis for caching:
281
+
282
+ ```javascript
283
+ import { Target } from 'te.js';
284
+ import dbManager from 'te.js/database/index.js';
285
+
286
+ const api = new Target('/api');
287
+
288
+ // Cache middleware
289
+ const withCache = (ttl = 60) => async (ammo, next) => {
290
+ if (!ammo.GET) return next();
291
+
292
+ const redis = dbManager.getConnection('redis');
293
+ const cacheKey = `cache:${ammo.endpoint}`;
294
+
295
+ // Try cache first
296
+ const cached = await redis.get(cacheKey);
297
+ if (cached) {
298
+ ammo.res.setHeader('X-Cache', 'HIT');
299
+ return ammo.fire(JSON.parse(cached));
300
+ }
301
+
302
+ // Store original fire to intercept
303
+ const originalFire = ammo.fire.bind(ammo);
304
+ ammo.fire = async (...args) => {
305
+ const data = args[0];
306
+ if (typeof data === 'object') {
307
+ await redis.setEx(cacheKey, ttl, JSON.stringify(data));
308
+ }
309
+ ammo.res.setHeader('X-Cache', 'MISS');
310
+ originalFire(...args);
311
+ };
312
+
313
+ next();
314
+ };
315
+
316
+ api.register('/expensive-data', withCache(300), async (ammo) => {
317
+ // This expensive operation result will be cached for 5 minutes
318
+ const data = await expensiveOperation();
319
+ ammo.fire(data);
320
+ });
321
+ ```
322
+
323
+ ## Session Storage with Redis
324
+
325
+ ```javascript
326
+ import { v4 as uuidv4 } from 'uuid';
327
+ import dbManager from 'te.js/database/index.js';
328
+
329
+ const sessionMiddleware = async (ammo, next) => {
330
+ const redis = dbManager.getConnection('redis');
331
+ let sessionId = ammo.headers['x-session-id'];
332
+
333
+ if (!sessionId) {
334
+ sessionId = uuidv4();
335
+ ammo.res.setHeader('X-Session-ID', sessionId);
336
+ ammo.session = {};
337
+ } else {
338
+ const sessionData = await redis.get(`session:${sessionId}`);
339
+ ammo.session = sessionData ? JSON.parse(sessionData) : {};
340
+ }
341
+
342
+ // Save session after response
343
+ const originalFire = ammo.fire.bind(ammo);
344
+ ammo.fire = async (...args) => {
345
+ await redis.setEx(
346
+ `session:${sessionId}`,
347
+ 3600, // 1 hour TTL
348
+ JSON.stringify(ammo.session)
349
+ );
350
+ originalFire(...args);
351
+ };
352
+
353
+ next();
354
+ };
355
+ ```
356
+
357
+ ## Connection Events
358
+
359
+ The underlying clients emit events you can listen to:
360
+
361
+ ```javascript
362
+ const redis = dbManager.getConnection('redis');
363
+
364
+ redis.on('error', (err) => {
365
+ console.error('Redis error:', err);
366
+ });
367
+
368
+ redis.on('connect', () => {
369
+ console.log('Redis connected');
370
+ });
371
+
372
+ redis.on('reconnecting', () => {
373
+ console.log('Redis reconnecting...');
374
+ });
375
+ ```
376
+
377
+ ## Best Practices
378
+
379
+ 1. **Initialize early** — Set up connections before `takeoff()`
380
+ 2. **Handle errors** — Always wrap database operations in try/catch
381
+ 3. **Use connection pooling** — MongoDB handles this automatically
382
+ 4. **Close on shutdown** — Clean up connections when app terminates
383
+
384
+ ```javascript
385
+ // Graceful shutdown
386
+ process.on('SIGTERM', async () => {
387
+ await dbManager.closeAllConnections();
388
+ process.exit(0);
389
+ });
390
+ ```