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
@@ -1,356 +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
356
-
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