te.js 2.1.0 → 2.1.2

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 (70) hide show
  1. package/README.md +197 -196
  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 -7
  6. package/auto-docs/docs-llm/prompts.js +222 -222
  7. package/auto-docs/docs-llm/provider.js +132 -132
  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/cors/index.js +71 -0
  20. package/database/index.js +165 -165
  21. package/database/mongodb.js +146 -146
  22. package/database/redis.js +201 -201
  23. package/docs/README.md +36 -36
  24. package/docs/ammo.md +362 -362
  25. package/docs/api-reference.md +490 -490
  26. package/docs/auto-docs.md +216 -216
  27. package/docs/cli.md +152 -152
  28. package/docs/configuration.md +275 -275
  29. package/docs/database.md +390 -390
  30. package/docs/error-handling.md +438 -438
  31. package/docs/file-uploads.md +333 -333
  32. package/docs/getting-started.md +214 -214
  33. package/docs/middleware.md +355 -355
  34. package/docs/rate-limiting.md +393 -393
  35. package/docs/routing.md +302 -302
  36. package/lib/llm/client.js +73 -0
  37. package/lib/llm/index.js +7 -0
  38. package/lib/llm/parse.js +89 -0
  39. package/package.json +64 -62
  40. package/rate-limit/algorithms/fixed-window.js +141 -141
  41. package/rate-limit/algorithms/sliding-window.js +147 -147
  42. package/rate-limit/algorithms/token-bucket.js +115 -115
  43. package/rate-limit/base.js +165 -165
  44. package/rate-limit/index.js +147 -147
  45. package/rate-limit/storage/base.js +104 -104
  46. package/rate-limit/storage/memory.js +101 -101
  47. package/rate-limit/storage/redis.js +88 -88
  48. package/server/ammo/body-parser.js +220 -220
  49. package/server/ammo/dispatch-helper.js +103 -103
  50. package/server/ammo/enhancer.js +57 -57
  51. package/server/ammo.js +454 -415
  52. package/server/endpoint.js +97 -74
  53. package/server/error.js +9 -9
  54. package/server/errors/code-context.js +125 -125
  55. package/server/errors/llm-error-service.js +140 -140
  56. package/server/files/helper.js +33 -33
  57. package/server/files/uploader.js +143 -143
  58. package/server/handler.js +158 -119
  59. package/server/target.js +185 -175
  60. package/server/targets/middleware-validator.js +22 -22
  61. package/server/targets/path-validator.js +21 -21
  62. package/server/targets/registry.js +160 -160
  63. package/server/targets/shoot-validator.js +21 -21
  64. package/te.js +428 -402
  65. package/utils/auto-register.js +17 -17
  66. package/utils/configuration.js +64 -64
  67. package/utils/errors-llm-config.js +84 -84
  68. package/utils/request-logger.js +43 -43
  69. package/utils/status-codes.js +82 -82
  70. package/utils/tejas-entrypoint-html.js +18 -18
@@ -1,355 +1,355 @@
1
- # Middleware
2
-
3
- Middleware functions in Tejas intercept requests before they reach your route handlers. They can modify the request, perform checks, or terminate the request early.
4
-
5
- ## Middleware Signature
6
-
7
- Tejas supports two middleware signatures:
8
-
9
- ### Tejas Style (Recommended)
10
-
11
- ```javascript
12
- const middleware = (ammo, next) => {
13
- // Do something
14
- next(); // Continue to next middleware/handler
15
- };
16
- ```
17
-
18
- ### Express Style (Compatible)
19
-
20
- ```javascript
21
- const middleware = (req, res, next) => {
22
- // Express-style middleware
23
- next();
24
- };
25
- ```
26
-
27
- Tejas automatically detects which style you're using based on the function's argument count: functions with 3 parameters are treated as Express-style `(req, res, next)`, while functions with 2 parameters are treated as Tejas-style `(ammo, next)`.
28
-
29
- ## Middleware Levels
30
-
31
- ### 1. Global Middleware
32
-
33
- Applied to **all routes** in your application:
34
-
35
- ```javascript
36
- import Tejas from 'te.js';
37
-
38
- const app = new Tejas();
39
-
40
- // Add global middleware
41
- app.midair((ammo, next) => {
42
- console.log(`[${new Date().toISOString()}] ${ammo.method} ${ammo.path}`);
43
- next();
44
- });
45
-
46
- // Multiple middleware in one call
47
- app.midair(
48
- loggingMiddleware,
49
- corsMiddleware,
50
- compressionMiddleware
51
- );
52
-
53
- app.takeoff();
54
- ```
55
-
56
- ### 2. Target Middleware
57
-
58
- Applied to **all routes in a Target**:
59
-
60
- ```javascript
61
- import { Target } from 'te.js';
62
-
63
- const api = new Target('/api');
64
-
65
- // All /api/* routes require authentication
66
- api.midair(authMiddleware);
67
-
68
- api.register('/users', handler); // Protected
69
- api.register('/posts', handler); // Protected
70
- api.register('/comments', handler); // Protected
71
- ```
72
-
73
- ### 3. Route Middleware
74
-
75
- Applied to a **specific route** only:
76
-
77
- ```javascript
78
- // Only /admin routes require admin privileges
79
- target.register('/admin', authMiddleware, adminMiddleware, (ammo) => {
80
- ammo.fire({ admin: 'panel' });
81
- });
82
-
83
- // Public route - no middleware
84
- target.register('/public', (ammo) => {
85
- ammo.fire({ public: true });
86
- });
87
- ```
88
-
89
- ## Execution Order
90
-
91
- Middleware executes in this order:
92
-
93
- ```
94
- Request
95
-
96
-
97
- ┌──────────────────┐
98
- │ Global Middleware │ (app.midair)
99
- └──────────────────┘
100
-
101
-
102
- ┌──────────────────┐
103
- │ Target Middleware │ (target.midair)
104
- └──────────────────┘
105
-
106
-
107
- ┌──────────────────┐
108
- │ Route Middleware │ (in register())
109
- └──────────────────┘
110
-
111
-
112
- ┌──────────────────┐
113
- │ Route Handler │
114
- └──────────────────┘
115
-
116
-
117
- Response
118
- ```
119
-
120
- ## Common Middleware Patterns
121
-
122
- ### Authentication
123
-
124
- ```javascript
125
- // middleware/auth.js
126
- import { TejError } from 'te.js';
127
-
128
- export const authMiddleware = async (ammo, next) => {
129
- const token = ammo.headers.authorization?.replace('Bearer ', '');
130
-
131
- if (!token) {
132
- throw new TejError(401, 'No token provided');
133
- }
134
-
135
- try {
136
- const user = await verifyToken(token);
137
- ammo.user = user; // Attach user to ammo
138
- next();
139
- } catch (error) {
140
- throw new TejError(401, 'Invalid token');
141
- }
142
- };
143
- ```
144
-
145
- ### Logging
146
-
147
- ```javascript
148
- // middleware/logging.js
149
- export const loggingMiddleware = (ammo, next) => {
150
- const start = Date.now();
151
-
152
- // Store original fire method
153
- const originalFire = ammo.fire.bind(ammo);
154
-
155
- // Override to log after response
156
- ammo.fire = (...args) => {
157
- const duration = Date.now() - start;
158
- console.log(`${ammo.method} ${ammo.path} - ${duration}ms`);
159
- originalFire(...args);
160
- };
161
-
162
- next();
163
- };
164
- ```
165
-
166
- ### CORS
167
-
168
- ```javascript
169
- // middleware/cors.js
170
- export const corsMiddleware = (ammo, next) => {
171
- ammo.res.setHeader('Access-Control-Allow-Origin', '*');
172
- ammo.res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
173
- ammo.res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
174
-
175
- // Handle preflight
176
- if (ammo.OPTIONS) {
177
- return ammo.fire(204);
178
- }
179
-
180
- next();
181
- };
182
- ```
183
-
184
- ### Rate Limiting Check
185
-
186
- ```javascript
187
- // middleware/rate-check.js
188
- export const rateLimitCheck = (ammo, next) => {
189
- const remaining = ammo.res.getHeader('RateLimit-Remaining');
190
-
191
- if (remaining && parseInt(remaining) < 10) {
192
- console.warn(`Low rate limit remaining for ${ammo.ip}`);
193
- }
194
-
195
- next();
196
- };
197
- ```
198
-
199
- ### Request Validation
200
-
201
- ```javascript
202
- // middleware/validate.js
203
- import { TejError } from 'te.js';
204
-
205
- export const validateBody = (schema) => {
206
- return (ammo, next) => {
207
- const errors = [];
208
-
209
- for (const [field, rules] of Object.entries(schema)) {
210
- const value = ammo.payload[field];
211
-
212
- if (rules.required && !value) {
213
- errors.push(`${field} is required`);
214
- }
215
-
216
- if (rules.type && typeof value !== rules.type) {
217
- errors.push(`${field} must be a ${rules.type}`);
218
- }
219
- }
220
-
221
- if (errors.length > 0) {
222
- throw new TejError(400, errors.join(', '));
223
- }
224
-
225
- next();
226
- };
227
- };
228
-
229
- // Usage
230
- target.register('/users',
231
- validateBody({
232
- name: { required: true, type: 'string' },
233
- email: { required: true, type: 'string' }
234
- }),
235
- (ammo) => {
236
- // Payload is validated
237
- ammo.fire(201, { created: true });
238
- }
239
- );
240
- ```
241
-
242
- ## Using Express Middleware
243
-
244
- Tejas is compatible with Express middleware:
245
-
246
- ```javascript
247
- import cors from 'cors';
248
- import helmet from 'helmet';
249
- import compression from 'compression';
250
-
251
- const app = new Tejas();
252
-
253
- // Express middleware works directly
254
- app.midair(cors());
255
- app.midair(helmet());
256
- app.midair(compression());
257
-
258
- app.takeoff();
259
- ```
260
-
261
- ### Passport.js Integration
262
-
263
- ```javascript
264
- import passport from 'passport';
265
-
266
- const app = new Tejas();
267
-
268
- // Initialize passport
269
- app.midair(passport.initialize());
270
-
271
- // In your target
272
- target.register('/auth/google',
273
- passport.authenticate('google', { scope: ['profile', 'email'] }),
274
- (ammo) => {
275
- // Redirect handled by passport
276
- }
277
- );
278
-
279
- target.register('/auth/google/callback',
280
- passport.authenticate('google', { session: false }),
281
- (ammo) => {
282
- ammo.fire({ user: ammo.req.user });
283
- }
284
- );
285
- ```
286
-
287
- ## Async Middleware
288
-
289
- Middleware can be async. Errors thrown inside async middleware are automatically caught by the framework:
290
-
291
- ```javascript
292
- const asyncMiddleware = async (ammo, next) => {
293
- const result = await someAsyncOperation();
294
- ammo.asyncResult = result;
295
- next();
296
- };
297
- ```
298
-
299
- ## Terminating Early
300
-
301
- To stop the middleware chain, send a response without calling `next()`. Once a response is sent (`ammo.fire()`, `ammo.throw()`, etc.), the framework detects that `res.headersSent` is `true` and stops executing further middleware or the handler:
302
-
303
- ```javascript
304
- const earlyReturn = (ammo, next) => {
305
- if (someCondition) {
306
- return ammo.fire(403, 'Forbidden');
307
- // next() is not called, chain stops
308
- }
309
-
310
- next(); // Continue chain
311
- };
312
- ```
313
-
314
- ## Middleware Factory Pattern
315
-
316
- Create configurable middleware:
317
-
318
- ```javascript
319
- // middleware/cache.js
320
- export const cache = (ttl = 60) => {
321
- const store = new Map();
322
-
323
- return (ammo, next) => {
324
- const key = ammo.path;
325
- const cached = store.get(key);
326
-
327
- if (cached && Date.now() - cached.time < ttl * 1000) {
328
- return ammo.fire(cached.data);
329
- }
330
-
331
- const originalFire = ammo.fire.bind(ammo);
332
- ammo.fire = (...args) => {
333
- store.set(key, { data: args[0], time: Date.now() });
334
- originalFire(...args);
335
- };
336
-
337
- next();
338
- };
339
- };
340
-
341
- // Usage
342
- target.register('/expensive', cache(300), (ammo) => {
343
- const data = expensiveComputation();
344
- ammo.fire(data);
345
- });
346
- ```
347
-
348
- ## Best Practices
349
-
350
- 1. **Keep middleware focused** — Each middleware should do one thing
351
- 2. **Always call next()** — Unless intentionally terminating the chain
352
- 3. **Handle errors** — Use try/catch in async middleware
353
- 4. **Use factories** — For configurable middleware
354
- 5. **Order matters** — Place authentication before authorization
355
- 6. **Don't mutate payload directly** — Add new properties instead
1
+ # Middleware
2
+
3
+ Middleware functions in Tejas intercept requests before they reach your route handlers. They can modify the request, perform checks, or terminate the request early.
4
+
5
+ ## Middleware Signature
6
+
7
+ Tejas supports two middleware signatures:
8
+
9
+ ### Tejas Style (Recommended)
10
+
11
+ ```javascript
12
+ const middleware = (ammo, next) => {
13
+ // Do something
14
+ next(); // Continue to next middleware/handler
15
+ };
16
+ ```
17
+
18
+ ### Express Style (Compatible)
19
+
20
+ ```javascript
21
+ const middleware = (req, res, next) => {
22
+ // Express-style middleware
23
+ next();
24
+ };
25
+ ```
26
+
27
+ Tejas automatically detects which style you're using based on the function's argument count: functions with 3 parameters are treated as Express-style `(req, res, next)`, while functions with 2 parameters are treated as Tejas-style `(ammo, next)`.
28
+
29
+ ## Middleware Levels
30
+
31
+ ### 1. Global Middleware
32
+
33
+ Applied to **all routes** in your application:
34
+
35
+ ```javascript
36
+ import Tejas from 'te.js';
37
+
38
+ const app = new Tejas();
39
+
40
+ // Add global middleware
41
+ app.midair((ammo, next) => {
42
+ console.log(`[${new Date().toISOString()}] ${ammo.method} ${ammo.path}`);
43
+ next();
44
+ });
45
+
46
+ // Multiple middleware in one call
47
+ app.midair(
48
+ loggingMiddleware,
49
+ corsMiddleware,
50
+ compressionMiddleware
51
+ );
52
+
53
+ app.takeoff();
54
+ ```
55
+
56
+ ### 2. Target Middleware
57
+
58
+ Applied to **all routes in a Target**:
59
+
60
+ ```javascript
61
+ import { Target } from 'te.js';
62
+
63
+ const api = new Target('/api');
64
+
65
+ // All /api/* routes require authentication
66
+ api.midair(authMiddleware);
67
+
68
+ api.register('/users', handler); // Protected
69
+ api.register('/posts', handler); // Protected
70
+ api.register('/comments', handler); // Protected
71
+ ```
72
+
73
+ ### 3. Route Middleware
74
+
75
+ Applied to a **specific route** only:
76
+
77
+ ```javascript
78
+ // Only /admin routes require admin privileges
79
+ target.register('/admin', authMiddleware, adminMiddleware, (ammo) => {
80
+ ammo.fire({ admin: 'panel' });
81
+ });
82
+
83
+ // Public route - no middleware
84
+ target.register('/public', (ammo) => {
85
+ ammo.fire({ public: true });
86
+ });
87
+ ```
88
+
89
+ ## Execution Order
90
+
91
+ Middleware executes in this order:
92
+
93
+ ```
94
+ Request
95
+
96
+
97
+ ┌──────────────────┐
98
+ │ Global Middleware │ (app.midair)
99
+ └──────────────────┘
100
+
101
+
102
+ ┌──────────────────┐
103
+ │ Target Middleware │ (target.midair)
104
+ └──────────────────┘
105
+
106
+
107
+ ┌──────────────────┐
108
+ │ Route Middleware │ (in register())
109
+ └──────────────────┘
110
+
111
+
112
+ ┌──────────────────┐
113
+ │ Route Handler │
114
+ └──────────────────┘
115
+
116
+
117
+ Response
118
+ ```
119
+
120
+ ## Common Middleware Patterns
121
+
122
+ ### Authentication
123
+
124
+ ```javascript
125
+ // middleware/auth.js
126
+ import { TejError } from 'te.js';
127
+
128
+ export const authMiddleware = async (ammo, next) => {
129
+ const token = ammo.headers.authorization?.replace('Bearer ', '');
130
+
131
+ if (!token) {
132
+ throw new TejError(401, 'No token provided');
133
+ }
134
+
135
+ try {
136
+ const user = await verifyToken(token);
137
+ ammo.user = user; // Attach user to ammo
138
+ next();
139
+ } catch (error) {
140
+ throw new TejError(401, 'Invalid token');
141
+ }
142
+ };
143
+ ```
144
+
145
+ ### Logging
146
+
147
+ ```javascript
148
+ // middleware/logging.js
149
+ export const loggingMiddleware = (ammo, next) => {
150
+ const start = Date.now();
151
+
152
+ // Store original fire method
153
+ const originalFire = ammo.fire.bind(ammo);
154
+
155
+ // Override to log after response
156
+ ammo.fire = (...args) => {
157
+ const duration = Date.now() - start;
158
+ console.log(`${ammo.method} ${ammo.path} - ${duration}ms`);
159
+ originalFire(...args);
160
+ };
161
+
162
+ next();
163
+ };
164
+ ```
165
+
166
+ ### CORS
167
+
168
+ ```javascript
169
+ // middleware/cors.js
170
+ export const corsMiddleware = (ammo, next) => {
171
+ ammo.res.setHeader('Access-Control-Allow-Origin', '*');
172
+ ammo.res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
173
+ ammo.res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
174
+
175
+ // Handle preflight
176
+ if (ammo.OPTIONS) {
177
+ return ammo.fire(204);
178
+ }
179
+
180
+ next();
181
+ };
182
+ ```
183
+
184
+ ### Rate Limiting Check
185
+
186
+ ```javascript
187
+ // middleware/rate-check.js
188
+ export const rateLimitCheck = (ammo, next) => {
189
+ const remaining = ammo.res.getHeader('RateLimit-Remaining');
190
+
191
+ if (remaining && parseInt(remaining) < 10) {
192
+ console.warn(`Low rate limit remaining for ${ammo.ip}`);
193
+ }
194
+
195
+ next();
196
+ };
197
+ ```
198
+
199
+ ### Request Validation
200
+
201
+ ```javascript
202
+ // middleware/validate.js
203
+ import { TejError } from 'te.js';
204
+
205
+ export const validateBody = (schema) => {
206
+ return (ammo, next) => {
207
+ const errors = [];
208
+
209
+ for (const [field, rules] of Object.entries(schema)) {
210
+ const value = ammo.payload[field];
211
+
212
+ if (rules.required && !value) {
213
+ errors.push(`${field} is required`);
214
+ }
215
+
216
+ if (rules.type && typeof value !== rules.type) {
217
+ errors.push(`${field} must be a ${rules.type}`);
218
+ }
219
+ }
220
+
221
+ if (errors.length > 0) {
222
+ throw new TejError(400, errors.join(', '));
223
+ }
224
+
225
+ next();
226
+ };
227
+ };
228
+
229
+ // Usage
230
+ target.register('/users',
231
+ validateBody({
232
+ name: { required: true, type: 'string' },
233
+ email: { required: true, type: 'string' }
234
+ }),
235
+ (ammo) => {
236
+ // Payload is validated
237
+ ammo.fire(201, { created: true });
238
+ }
239
+ );
240
+ ```
241
+
242
+ ## Using Express Middleware
243
+
244
+ Tejas is compatible with Express middleware:
245
+
246
+ ```javascript
247
+ import cors from 'cors';
248
+ import helmet from 'helmet';
249
+ import compression from 'compression';
250
+
251
+ const app = new Tejas();
252
+
253
+ // Express middleware works directly
254
+ app.midair(cors());
255
+ app.midair(helmet());
256
+ app.midair(compression());
257
+
258
+ app.takeoff();
259
+ ```
260
+
261
+ ### Passport.js Integration
262
+
263
+ ```javascript
264
+ import passport from 'passport';
265
+
266
+ const app = new Tejas();
267
+
268
+ // Initialize passport
269
+ app.midair(passport.initialize());
270
+
271
+ // In your target
272
+ target.register('/auth/google',
273
+ passport.authenticate('google', { scope: ['profile', 'email'] }),
274
+ (ammo) => {
275
+ // Redirect handled by passport
276
+ }
277
+ );
278
+
279
+ target.register('/auth/google/callback',
280
+ passport.authenticate('google', { session: false }),
281
+ (ammo) => {
282
+ ammo.fire({ user: ammo.req.user });
283
+ }
284
+ );
285
+ ```
286
+
287
+ ## Async Middleware
288
+
289
+ Middleware can be async. Errors thrown inside async middleware are automatically caught by the framework:
290
+
291
+ ```javascript
292
+ const asyncMiddleware = async (ammo, next) => {
293
+ const result = await someAsyncOperation();
294
+ ammo.asyncResult = result;
295
+ next();
296
+ };
297
+ ```
298
+
299
+ ## Terminating Early
300
+
301
+ To stop the middleware chain, send a response without calling `next()`. Once a response is sent (`ammo.fire()`, `ammo.throw()`, etc.), the framework detects that `res.headersSent` is `true` and stops executing further middleware or the handler:
302
+
303
+ ```javascript
304
+ const earlyReturn = (ammo, next) => {
305
+ if (someCondition) {
306
+ return ammo.fire(403, 'Forbidden');
307
+ // next() is not called, chain stops
308
+ }
309
+
310
+ next(); // Continue chain
311
+ };
312
+ ```
313
+
314
+ ## Middleware Factory Pattern
315
+
316
+ Create configurable middleware:
317
+
318
+ ```javascript
319
+ // middleware/cache.js
320
+ export const cache = (ttl = 60) => {
321
+ const store = new Map();
322
+
323
+ return (ammo, next) => {
324
+ const key = ammo.path;
325
+ const cached = store.get(key);
326
+
327
+ if (cached && Date.now() - cached.time < ttl * 1000) {
328
+ return ammo.fire(cached.data);
329
+ }
330
+
331
+ const originalFire = ammo.fire.bind(ammo);
332
+ ammo.fire = (...args) => {
333
+ store.set(key, { data: args[0], time: Date.now() });
334
+ originalFire(...args);
335
+ };
336
+
337
+ next();
338
+ };
339
+ };
340
+
341
+ // Usage
342
+ target.register('/expensive', cache(300), (ammo) => {
343
+ const data = expensiveComputation();
344
+ ammo.fire(data);
345
+ });
346
+ ```
347
+
348
+ ## Best Practices
349
+
350
+ 1. **Keep middleware focused** — Each middleware should do one thing
351
+ 2. **Always call next()** — Unless intentionally terminating the chain
352
+ 3. **Handle errors** — Use try/catch in async middleware
353
+ 4. **Use factories** — For configurable middleware
354
+ 5. **Order matters** — Place authentication before authorization
355
+ 6. **Don't mutate payload directly** — Add new properties instead