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,490 +1,490 @@
1
- # API Reference
2
-
3
- Complete API documentation for the Tejas framework.
4
-
5
- ---
6
-
7
- ## Tejas Class
8
-
9
- The main application class. Only one instance exists per process (singleton).
10
-
11
- ### Constructor
12
-
13
- ```javascript
14
- import Tejas from 'te.js';
15
-
16
- const app = new Tejas(options);
17
- ```
18
-
19
- #### Options
20
-
21
- | Option | Type | Default | Description |
22
- |--------|------|---------|-------------|
23
- | `entry` | string | *(auto-resolved)* | Entry file for `tejas fly` |
24
- | `port` | number | `1403` | Server port |
25
- | `log.http_requests` | boolean | `false` | Enable request logging |
26
- | `log.exceptions` | boolean | `false` | Enable error logging |
27
- | `body.max_size` | number | `10485760` (10 MB) | Max body size (bytes) |
28
- | `body.timeout` | number | `30000` (30 s) | Body parsing timeout (ms) |
29
- | `dir.targets` | string | `"targets"` | Directory for auto-discovered `.target.js` files |
30
-
31
- See [Configuration](./configuration.md) for all options including the `docs` section.
32
-
33
- ### Methods
34
-
35
- #### midair(...middlewares)
36
-
37
- Register global middleware. These run for every incoming request.
38
-
39
- ```javascript
40
- app.midair(middleware1, middleware2);
41
- ```
42
-
43
- #### withRedis(config)
44
-
45
- Initialize a Redis connection. Auto-installs the `redis` package if needed.
46
-
47
- ```javascript
48
- app.withRedis({
49
- url: 'redis://localhost:6379',
50
- isCluster: false
51
- });
52
- ```
53
-
54
- | Option | Type | Default | Description |
55
- |--------|------|---------|-------------|
56
- | `url` | string | — | Redis connection URL |
57
- | `isCluster` | boolean | `false` | Use Redis Cluster |
58
- | `socket.host` | string | — | Redis host |
59
- | `socket.port` | number | — | Redis port |
60
- | `socket.tls` | boolean | `false` | Use TLS |
61
- | `password` | string | — | Redis password |
62
-
63
- **Returns:** `Promise<Tejas>` (for chaining)
64
-
65
- #### withMongo(config)
66
-
67
- Initialize a MongoDB connection. Auto-installs `mongoose` if needed.
68
-
69
- ```javascript
70
- app.withMongo({
71
- uri: 'mongodb://localhost:27017/myapp'
72
- });
73
- ```
74
-
75
- | Option | Type | Description |
76
- |--------|------|-------------|
77
- | `uri` | string | MongoDB connection URI |
78
-
79
- **Returns:** `Tejas` (for chaining)
80
-
81
- #### withRateLimit(config)
82
-
83
- Enable global rate limiting.
84
-
85
- ```javascript
86
- app.withRateLimit({
87
- maxRequests: 100,
88
- timeWindowSeconds: 60,
89
- algorithm: 'sliding-window',
90
- store: 'memory'
91
- });
92
- ```
93
-
94
- | Option | Type | Default | Description |
95
- |--------|------|---------|-------------|
96
- | `maxRequests` | number | `60` | Max requests per window |
97
- | `timeWindowSeconds` | number | `60` | Time window in seconds |
98
- | `algorithm` | string | `'sliding-window'` | `'sliding-window'`, `'token-bucket'`, or `'fixed-window'` |
99
- | `store` | string | `'memory'` | `'memory'` or `'redis'` |
100
- | `keyGenerator` | function | `(ammo) => ammo.ip` | Generates unique key per client |
101
- | `keyPrefix` | string | `'rl:'` | Storage key prefix |
102
- | `headerFormat.type` | string | `'standard'` | `'standard'`, `'legacy'`, or `'both'` |
103
- | `headerFormat.draft7` | boolean | `false` | Include `RateLimit-Policy` header |
104
- | `headerFormat.draft8` | boolean | `false` | Use delta-seconds for `RateLimit-Reset` |
105
- | `onRateLimited` | function | — | Custom handler when rate limited |
106
-
107
- **Returns:** `Tejas` (for chaining)
108
-
109
- #### serveDocs(config)
110
-
111
- Serve an interactive API documentation UI (Scalar) from a pre-generated OpenAPI spec.
112
-
113
- ```javascript
114
- app.serveDocs({
115
- specPath: './openapi.json',
116
- scalarConfig: { layout: 'modern', theme: 'default' }
117
- });
118
- ```
119
-
120
- | Option | Type | Default | Description |
121
- |--------|------|---------|-------------|
122
- | `specPath` | string | `'./openapi.json'` | Path to the OpenAPI spec file |
123
- | `scalarConfig` | object | *(defaults)* | Scalar UI configuration options |
124
-
125
- Registers `GET /docs` (HTML UI) and `GET /docs/openapi.json` (spec JSON).
126
-
127
- **Returns:** `Tejas` (for chaining)
128
-
129
- #### takeoff(options)
130
-
131
- Start the HTTP server. Optionally initializes database connections.
132
-
133
- ```javascript
134
- app.takeoff();
135
-
136
- app.takeoff({
137
- withRedis: { url: 'redis://localhost:6379' },
138
- withMongo: { uri: 'mongodb://localhost:27017/db' }
139
- });
140
- ```
141
-
142
- ---
143
-
144
- ## Target Class
145
-
146
- Route grouping class (equivalent to Express `Router`).
147
-
148
- ### Constructor
149
-
150
- ```javascript
151
- import { Target } from 'te.js';
152
-
153
- const target = new Target(basePath);
154
- ```
155
-
156
- | Parameter | Type | Default | Description |
157
- |-----------|------|---------|-------------|
158
- | `basePath` | string | `''` | Base path for all routes in this target |
159
-
160
- ### Methods
161
-
162
- #### midair(...middlewares)
163
-
164
- Add target-level middleware that runs for all routes in this target.
165
-
166
- ```javascript
167
- target.midair(authMiddleware, loggingMiddleware);
168
- ```
169
-
170
- #### register(path, [metadata], ...middlewares, handler)
171
-
172
- Register an endpoint.
173
-
174
- ```javascript
175
- // Basic
176
- target.register('/path', handler);
177
-
178
- // With middleware
179
- target.register('/path', middleware1, middleware2, handler);
180
-
181
- // With metadata (for auto-docs)
182
- target.register('/path', {
183
- summary: 'Description',
184
- methods: ['GET', 'POST'],
185
- request: { name: { type: 'string', required: true } },
186
- response: { 200: { description: 'Success' } }
187
- }, middleware1, handler);
188
- ```
189
-
190
- | Parameter | Type | Description |
191
- |-----------|------|-------------|
192
- | `path` | string | Route path (supports `:param` for parameters) |
193
- | `metadata` | object | *(optional)* Metadata for OpenAPI generation |
194
- | `middlewares` | function[] | *(optional)* Route-specific middleware |
195
- | `handler` | function | Route handler `(ammo) => {}` (always the last argument) |
196
-
197
- ---
198
-
199
- ## Ammo Class
200
-
201
- Request/response wrapper created for each incoming request.
202
-
203
- ### Properties
204
-
205
- #### HTTP Method Flags
206
-
207
- | Property | Type | Description |
208
- |----------|------|-------------|
209
- | `GET` | boolean | `true` if GET request |
210
- | `POST` | boolean | `true` if POST request |
211
- | `PUT` | boolean | `true` if PUT request |
212
- | `DELETE` | boolean | `true` if DELETE request |
213
- | `PATCH` | boolean | `true` if PATCH request |
214
- | `HEAD` | boolean | `true` if HEAD request |
215
- | `OPTIONS` | boolean | `true` if OPTIONS request |
216
-
217
- #### Request Data
218
-
219
- | Property | Type | Description |
220
- |----------|------|-------------|
221
- | `method` | string | HTTP method string (e.g. `'GET'`) |
222
- | `payload` | object | Merged: query params + body + route params (route params have highest priority) |
223
- | `headers` | object | Request headers (lowercase keys) |
224
- | `ip` | string | Client IP address |
225
-
226
- #### URL Data
227
-
228
- | Property | Type | Description |
229
- |----------|------|-------------|
230
- | `path` | string | Full URL path with query string |
231
- | `endpoint` | string | Path without query string |
232
- | `protocol` | string | `'http'` or `'https'` |
233
- | `hostname` | string | Request hostname |
234
- | `fullURL` | string | Complete URL |
235
-
236
- #### Raw Objects
237
-
238
- | Property | Type | Description |
239
- |----------|------|-------------|
240
- | `req` | IncomingMessage | Node.js request object |
241
- | `res` | ServerResponse | Node.js response object |
242
-
243
- #### Response Data
244
-
245
- | Property | Type | Description |
246
- |----------|------|-------------|
247
- | `dispatchedData` | any | The data sent via the most recent `fire()` call. `undefined` until `fire()` is called |
248
-
249
- ### Methods
250
-
251
- #### fire()
252
-
253
- Send a response to the client.
254
-
255
- | Signature | Status | Body | Content-Type |
256
- |-----------|--------|------|-------------|
257
- | `fire()` | 204 | *(empty)* | — |
258
- | `fire("text")` | 200 | text | `text/plain` |
259
- | `fire({ json })` | 200 | JSON string | `application/json` |
260
- | `fire(201)` | 201 | status message | `text/plain` |
261
- | `fire(201, data)` | 201 | data | auto-detected |
262
- | `fire(200, html, "text/html")` | 200 | html | `text/html` |
263
-
264
- #### throw()
265
-
266
- Send an error response. When [LLM-inferred errors](./error-handling.md#llm-inferred-errors) are enabled (`errors.llm.enabled`), calls without explicit status code or message use an LLM to infer code and message; explicit code/message always override.
267
-
268
- | Signature | Behavior |
269
- |-----------|----------|
270
- | `throw()` | 500 "Internal Server Error" (or LLM-inferred when `errors.llm.enabled`) |
271
- | `throw(404)` | 404 with default status message |
272
- | `throw(404, "msg")` | 404 with custom message |
273
- | `throw(new TejError(code, msg))` | Uses TejError's code and message |
274
- | `throw(new Error("msg"))` | 500 with error message, or LLM-inferred when `errors.llm.enabled` |
275
- | LLM-inferred (no explicit code/message, `errors.llm.enabled`) | Status and message derived by LLM from context |
276
-
277
- #### redirect(url, statusCode)
278
-
279
- HTTP redirect.
280
-
281
- ```javascript
282
- ammo.redirect('/new-path'); // 302 temporary
283
- ammo.redirect('/new-path', 301); // 301 permanent
284
- ```
285
-
286
- | Parameter | Type | Default | Description |
287
- |-----------|------|---------|-------------|
288
- | `url` | string | — | Redirect URL |
289
- | `statusCode` | number | `302` | HTTP status code |
290
-
291
- #### notFound()
292
-
293
- Throws 404 Not Found.
294
-
295
- #### notAllowed()
296
-
297
- Throws 405 Method Not Allowed.
298
-
299
- #### unauthorized()
300
-
301
- Throws 401 Unauthorized.
302
-
303
- #### defaultEntry()
304
-
305
- Sends the default Tejas HTML entry page. Used internally for the root `/` route when no target matches.
306
-
307
- ---
308
-
309
- ## TejError Class
310
-
311
- Custom error class for HTTP errors. Use it when you want to set the response explicitly; both status code and message are optional when errors are passed through `ammo.throw()` with [LLM-inferred errors](./error-handling.md#llm-inferred-errors) enabled (the LLM can infer them).
312
-
313
- ```javascript
314
- import { TejError } from 'te.js';
315
-
316
- throw new TejError(statusCode, message);
317
- ```
318
-
319
- | Parameter | Type | Description |
320
- |-----------|------|-------------|
321
- | `statusCode` | number | HTTP status code (optional when LLM infers; otherwise use for override) |
322
- | `message` | string | Error message (optional when LLM infers; otherwise use for override) |
323
-
324
- | Property | Type | Description |
325
- |----------|------|-------------|
326
- | `code` | number | HTTP status code |
327
- | `message` | string | Error message |
328
- | `name` | string | `'TejError'` |
329
-
330
- ### BodyParserError
331
-
332
- A subclass of `TejError` thrown during request body parsing:
333
-
334
- | Status | Condition |
335
- |--------|-----------|
336
- | 400 | Malformed JSON, invalid URL-encoded data, or corrupted multipart data |
337
- | 408 | Body parsing timed out |
338
- | 413 | Request body exceeds `body.max_size` |
339
- | 415 | Unsupported content type |
340
-
341
- ---
342
-
343
- ## TejFileUploader Class
344
-
345
- File upload handler as middleware.
346
-
347
- ### Constructor
348
-
349
- ```javascript
350
- import { TejFileUploader } from 'te.js';
351
-
352
- const upload = new TejFileUploader(options);
353
- ```
354
-
355
- | Option | Type | Description |
356
- |--------|------|-------------|
357
- | `destination` | string | Directory to save uploaded files |
358
- | `name` | string | Optional custom filename |
359
- | `maxFileSize` | number | Max file size in bytes (throws 413 if exceeded) |
360
-
361
- ### Methods
362
-
363
- #### file(...fieldNames)
364
-
365
- Returns middleware for single file upload per field.
366
-
367
- ```javascript
368
- target.register('/upload', upload.file('avatar'), handler);
369
- ```
370
-
371
- #### files(...fieldNames)
372
-
373
- Returns middleware for multiple files per field, grouped by field name.
374
-
375
- ```javascript
376
- target.register('/upload', upload.files('photos', 'documents'), handler);
377
- ```
378
-
379
- ### Uploaded File Object
380
-
381
- ```javascript
382
- {
383
- filename: string, // Original filename
384
- extension: string, // File extension
385
- path: {
386
- absolute: string, // Absolute path on disk
387
- relative: string // Relative to cwd
388
- },
389
- mimetype: string, // MIME type
390
- size: {
391
- value: number, // Numeric size value
392
- symbol: string // Unit: 'B', 'KB', 'MB', etc.
393
- }
394
- }
395
- ```
396
-
397
- ---
398
-
399
- ## Utility Functions
400
-
401
- ### listAllEndpoints(grouped)
402
-
403
- Get all registered endpoints.
404
-
405
- ```javascript
406
- import { listAllEndpoints } from 'te.js';
407
-
408
- const routes = listAllEndpoints(); // ['/', '/users', '/api/data']
409
- const grouped = listAllEndpoints(true); // { users: [...], api: [...] }
410
- ```
411
-
412
- | Parameter | Type | Default | Description |
413
- |-----------|------|---------|-------------|
414
- | `grouped` | boolean | `false` | Group by first path segment |
415
-
416
- ---
417
-
418
- ## Middleware Signatures
419
-
420
- Tejas detects the middleware style by argument count:
421
-
422
- ### Tejas Style (2 arguments)
423
-
424
- ```javascript
425
- const middleware = (ammo, next) => {
426
- // Access ammo properties
427
- next();
428
- };
429
- ```
430
-
431
- ### Express Style (3 arguments)
432
-
433
- ```javascript
434
- const middleware = (req, res, next) => {
435
- // Access req, res directly
436
- next();
437
- };
438
- ```
439
-
440
- ---
441
-
442
- ## Environment Access
443
-
444
- ```javascript
445
- import { env, setEnv } from 'tej-env';
446
-
447
- const port = env('PORT');
448
- setEnv('CUSTOM_VAR', 'value');
449
- ```
450
-
451
- ---
452
-
453
- ## Database Manager
454
-
455
- ```javascript
456
- import dbManager from 'te.js/database/index.js';
457
-
458
- // Get connection
459
- const redis = dbManager.getConnection('redis');
460
- const mongo = dbManager.getConnection('mongodb');
461
-
462
- // Check connection status
463
- const status = dbManager.hasConnection('redis', {});
464
- // { exists: boolean, initializing: boolean }
465
-
466
- // Close connections
467
- await dbManager.closeConnection('redis');
468
- await dbManager.closeAllConnections();
469
-
470
- // Get all active connections
471
- const connections = dbManager.getActiveConnections();
472
- // Returns: Map
473
- ```
474
-
475
- ---
476
-
477
- ## RateLimitStorage Base Class
478
-
479
- Abstract base class for custom rate limit storage backends:
480
-
481
- ```javascript
482
- import RateLimitStorage from 'te.js/rate-limit/storage/base.js';
483
-
484
- class CustomStorage extends RateLimitStorage {
485
- async get(key) { } // Return object or null
486
- async set(key, value, ttl) { } // Store with TTL (seconds)
487
- async increment(key) { } // Return new value or null
488
- async delete(key) { } // Remove key
489
- }
490
- ```
1
+ # API Reference
2
+
3
+ Complete API documentation for the Tejas framework.
4
+
5
+ ---
6
+
7
+ ## Tejas Class
8
+
9
+ The main application class. Only one instance exists per process (singleton).
10
+
11
+ ### Constructor
12
+
13
+ ```javascript
14
+ import Tejas from 'te.js';
15
+
16
+ const app = new Tejas(options);
17
+ ```
18
+
19
+ #### Options
20
+
21
+ | Option | Type | Default | Description |
22
+ |--------|------|---------|-------------|
23
+ | `entry` | string | *(auto-resolved)* | Entry file for `tejas fly` |
24
+ | `port` | number | `1403` | Server port |
25
+ | `log.http_requests` | boolean | `false` | Enable request logging |
26
+ | `log.exceptions` | boolean | `false` | Enable error logging |
27
+ | `body.max_size` | number | `10485760` (10 MB) | Max body size (bytes) |
28
+ | `body.timeout` | number | `30000` (30 s) | Body parsing timeout (ms) |
29
+ | `dir.targets` | string | `"targets"` | Directory for auto-discovered `.target.js` files |
30
+
31
+ See [Configuration](./configuration.md) for all options including the `docs` section.
32
+
33
+ ### Methods
34
+
35
+ #### midair(...middlewares)
36
+
37
+ Register global middleware. These run for every incoming request.
38
+
39
+ ```javascript
40
+ app.midair(middleware1, middleware2);
41
+ ```
42
+
43
+ #### withRedis(config)
44
+
45
+ Initialize a Redis connection. Auto-installs the `redis` package if needed.
46
+
47
+ ```javascript
48
+ app.withRedis({
49
+ url: 'redis://localhost:6379',
50
+ isCluster: false
51
+ });
52
+ ```
53
+
54
+ | Option | Type | Default | Description |
55
+ |--------|------|---------|-------------|
56
+ | `url` | string | — | Redis connection URL |
57
+ | `isCluster` | boolean | `false` | Use Redis Cluster |
58
+ | `socket.host` | string | — | Redis host |
59
+ | `socket.port` | number | — | Redis port |
60
+ | `socket.tls` | boolean | `false` | Use TLS |
61
+ | `password` | string | — | Redis password |
62
+
63
+ **Returns:** `Promise<Tejas>` (for chaining)
64
+
65
+ #### withMongo(config)
66
+
67
+ Initialize a MongoDB connection. Auto-installs `mongoose` if needed.
68
+
69
+ ```javascript
70
+ app.withMongo({
71
+ uri: 'mongodb://localhost:27017/myapp'
72
+ });
73
+ ```
74
+
75
+ | Option | Type | Description |
76
+ |--------|------|-------------|
77
+ | `uri` | string | MongoDB connection URI |
78
+
79
+ **Returns:** `Tejas` (for chaining)
80
+
81
+ #### withRateLimit(config)
82
+
83
+ Enable global rate limiting.
84
+
85
+ ```javascript
86
+ app.withRateLimit({
87
+ maxRequests: 100,
88
+ timeWindowSeconds: 60,
89
+ algorithm: 'sliding-window',
90
+ store: 'memory'
91
+ });
92
+ ```
93
+
94
+ | Option | Type | Default | Description |
95
+ |--------|------|---------|-------------|
96
+ | `maxRequests` | number | `60` | Max requests per window |
97
+ | `timeWindowSeconds` | number | `60` | Time window in seconds |
98
+ | `algorithm` | string | `'sliding-window'` | `'sliding-window'`, `'token-bucket'`, or `'fixed-window'` |
99
+ | `store` | string | `'memory'` | `'memory'` or `'redis'` |
100
+ | `keyGenerator` | function | `(ammo) => ammo.ip` | Generates unique key per client |
101
+ | `keyPrefix` | string | `'rl:'` | Storage key prefix |
102
+ | `headerFormat.type` | string | `'standard'` | `'standard'`, `'legacy'`, or `'both'` |
103
+ | `headerFormat.draft7` | boolean | `false` | Include `RateLimit-Policy` header |
104
+ | `headerFormat.draft8` | boolean | `false` | Use delta-seconds for `RateLimit-Reset` |
105
+ | `onRateLimited` | function | — | Custom handler when rate limited |
106
+
107
+ **Returns:** `Tejas` (for chaining)
108
+
109
+ #### serveDocs(config)
110
+
111
+ Serve an interactive API documentation UI (Scalar) from a pre-generated OpenAPI spec.
112
+
113
+ ```javascript
114
+ app.serveDocs({
115
+ specPath: './openapi.json',
116
+ scalarConfig: { layout: 'modern', theme: 'default' }
117
+ });
118
+ ```
119
+
120
+ | Option | Type | Default | Description |
121
+ |--------|------|---------|-------------|
122
+ | `specPath` | string | `'./openapi.json'` | Path to the OpenAPI spec file |
123
+ | `scalarConfig` | object | *(defaults)* | Scalar UI configuration options |
124
+
125
+ Registers `GET /docs` (HTML UI) and `GET /docs/openapi.json` (spec JSON).
126
+
127
+ **Returns:** `Tejas` (for chaining)
128
+
129
+ #### takeoff(options)
130
+
131
+ Start the HTTP server. Optionally initializes database connections.
132
+
133
+ ```javascript
134
+ app.takeoff();
135
+
136
+ app.takeoff({
137
+ withRedis: { url: 'redis://localhost:6379' },
138
+ withMongo: { uri: 'mongodb://localhost:27017/db' }
139
+ });
140
+ ```
141
+
142
+ ---
143
+
144
+ ## Target Class
145
+
146
+ Route grouping class (equivalent to Express `Router`).
147
+
148
+ ### Constructor
149
+
150
+ ```javascript
151
+ import { Target } from 'te.js';
152
+
153
+ const target = new Target(basePath);
154
+ ```
155
+
156
+ | Parameter | Type | Default | Description |
157
+ |-----------|------|---------|-------------|
158
+ | `basePath` | string | `''` | Base path for all routes in this target |
159
+
160
+ ### Methods
161
+
162
+ #### midair(...middlewares)
163
+
164
+ Add target-level middleware that runs for all routes in this target.
165
+
166
+ ```javascript
167
+ target.midair(authMiddleware, loggingMiddleware);
168
+ ```
169
+
170
+ #### register(path, [metadata], ...middlewares, handler)
171
+
172
+ Register an endpoint.
173
+
174
+ ```javascript
175
+ // Basic
176
+ target.register('/path', handler);
177
+
178
+ // With middleware
179
+ target.register('/path', middleware1, middleware2, handler);
180
+
181
+ // With metadata (for auto-docs)
182
+ target.register('/path', {
183
+ summary: 'Description',
184
+ methods: ['GET', 'POST'],
185
+ request: { name: { type: 'string', required: true } },
186
+ response: { 200: { description: 'Success' } }
187
+ }, middleware1, handler);
188
+ ```
189
+
190
+ | Parameter | Type | Description |
191
+ |-----------|------|-------------|
192
+ | `path` | string | Route path (supports `:param` for parameters) |
193
+ | `metadata` | object | *(optional)* Metadata for OpenAPI generation |
194
+ | `middlewares` | function[] | *(optional)* Route-specific middleware |
195
+ | `handler` | function | Route handler `(ammo) => {}` (always the last argument) |
196
+
197
+ ---
198
+
199
+ ## Ammo Class
200
+
201
+ Request/response wrapper created for each incoming request.
202
+
203
+ ### Properties
204
+
205
+ #### HTTP Method Flags
206
+
207
+ | Property | Type | Description |
208
+ |----------|------|-------------|
209
+ | `GET` | boolean | `true` if GET request |
210
+ | `POST` | boolean | `true` if POST request |
211
+ | `PUT` | boolean | `true` if PUT request |
212
+ | `DELETE` | boolean | `true` if DELETE request |
213
+ | `PATCH` | boolean | `true` if PATCH request |
214
+ | `HEAD` | boolean | `true` if HEAD request |
215
+ | `OPTIONS` | boolean | `true` if OPTIONS request |
216
+
217
+ #### Request Data
218
+
219
+ | Property | Type | Description |
220
+ |----------|------|-------------|
221
+ | `method` | string | HTTP method string (e.g. `'GET'`) |
222
+ | `payload` | object | Merged: query params + body + route params (route params have highest priority) |
223
+ | `headers` | object | Request headers (lowercase keys) |
224
+ | `ip` | string | Client IP address |
225
+
226
+ #### URL Data
227
+
228
+ | Property | Type | Description |
229
+ |----------|------|-------------|
230
+ | `path` | string | Full URL path with query string |
231
+ | `endpoint` | string | Path without query string |
232
+ | `protocol` | string | `'http'` or `'https'` |
233
+ | `hostname` | string | Request hostname |
234
+ | `fullURL` | string | Complete URL |
235
+
236
+ #### Raw Objects
237
+
238
+ | Property | Type | Description |
239
+ |----------|------|-------------|
240
+ | `req` | IncomingMessage | Node.js request object |
241
+ | `res` | ServerResponse | Node.js response object |
242
+
243
+ #### Response Data
244
+
245
+ | Property | Type | Description |
246
+ |----------|------|-------------|
247
+ | `dispatchedData` | any | The data sent via the most recent `fire()` call. `undefined` until `fire()` is called |
248
+
249
+ ### Methods
250
+
251
+ #### fire()
252
+
253
+ Send a response to the client.
254
+
255
+ | Signature | Status | Body | Content-Type |
256
+ |-----------|--------|------|-------------|
257
+ | `fire()` | 204 | *(empty)* | — |
258
+ | `fire("text")` | 200 | text | `text/plain` |
259
+ | `fire({ json })` | 200 | JSON string | `application/json` |
260
+ | `fire(201)` | 201 | status message | `text/plain` |
261
+ | `fire(201, data)` | 201 | data | auto-detected |
262
+ | `fire(200, html, "text/html")` | 200 | html | `text/html` |
263
+
264
+ #### throw()
265
+
266
+ Send an error response. When [LLM-inferred errors](./error-handling.md#llm-inferred-errors) are enabled (`errors.llm.enabled`), calls without explicit status code or message use an LLM to infer code and message; explicit code/message always override.
267
+
268
+ | Signature | Behavior |
269
+ |-----------|----------|
270
+ | `throw()` | 500 "Internal Server Error" (or LLM-inferred when `errors.llm.enabled`) |
271
+ | `throw(404)` | 404 with default status message |
272
+ | `throw(404, "msg")` | 404 with custom message |
273
+ | `throw(new TejError(code, msg))` | Uses TejError's code and message |
274
+ | `throw(new Error("msg"))` | 500 with error message, or LLM-inferred when `errors.llm.enabled` |
275
+ | LLM-inferred (no explicit code/message, `errors.llm.enabled`) | Status and message derived by LLM from context |
276
+
277
+ #### redirect(url, statusCode)
278
+
279
+ HTTP redirect.
280
+
281
+ ```javascript
282
+ ammo.redirect('/new-path'); // 302 temporary
283
+ ammo.redirect('/new-path', 301); // 301 permanent
284
+ ```
285
+
286
+ | Parameter | Type | Default | Description |
287
+ |-----------|------|---------|-------------|
288
+ | `url` | string | — | Redirect URL |
289
+ | `statusCode` | number | `302` | HTTP status code |
290
+
291
+ #### notFound()
292
+
293
+ Throws 404 Not Found.
294
+
295
+ #### notAllowed()
296
+
297
+ Throws 405 Method Not Allowed.
298
+
299
+ #### unauthorized()
300
+
301
+ Throws 401 Unauthorized.
302
+
303
+ #### defaultEntry()
304
+
305
+ Sends the default Tejas HTML entry page. Used internally for the root `/` route when no target matches.
306
+
307
+ ---
308
+
309
+ ## TejError Class
310
+
311
+ Custom error class for HTTP errors. Use it when you want to set the response explicitly; both status code and message are optional when errors are passed through `ammo.throw()` with [LLM-inferred errors](./error-handling.md#llm-inferred-errors) enabled (the LLM can infer them).
312
+
313
+ ```javascript
314
+ import { TejError } from 'te.js';
315
+
316
+ throw new TejError(statusCode, message);
317
+ ```
318
+
319
+ | Parameter | Type | Description |
320
+ |-----------|------|-------------|
321
+ | `statusCode` | number | HTTP status code (optional when LLM infers; otherwise use for override) |
322
+ | `message` | string | Error message (optional when LLM infers; otherwise use for override) |
323
+
324
+ | Property | Type | Description |
325
+ |----------|------|-------------|
326
+ | `code` | number | HTTP status code |
327
+ | `message` | string | Error message |
328
+ | `name` | string | `'TejError'` |
329
+
330
+ ### BodyParserError
331
+
332
+ A subclass of `TejError` thrown during request body parsing:
333
+
334
+ | Status | Condition |
335
+ |--------|-----------|
336
+ | 400 | Malformed JSON, invalid URL-encoded data, or corrupted multipart data |
337
+ | 408 | Body parsing timed out |
338
+ | 413 | Request body exceeds `body.max_size` |
339
+ | 415 | Unsupported content type |
340
+
341
+ ---
342
+
343
+ ## TejFileUploader Class
344
+
345
+ File upload handler as middleware.
346
+
347
+ ### Constructor
348
+
349
+ ```javascript
350
+ import { TejFileUploader } from 'te.js';
351
+
352
+ const upload = new TejFileUploader(options);
353
+ ```
354
+
355
+ | Option | Type | Description |
356
+ |--------|------|-------------|
357
+ | `destination` | string | Directory to save uploaded files |
358
+ | `name` | string | Optional custom filename |
359
+ | `maxFileSize` | number | Max file size in bytes (throws 413 if exceeded) |
360
+
361
+ ### Methods
362
+
363
+ #### file(...fieldNames)
364
+
365
+ Returns middleware for single file upload per field.
366
+
367
+ ```javascript
368
+ target.register('/upload', upload.file('avatar'), handler);
369
+ ```
370
+
371
+ #### files(...fieldNames)
372
+
373
+ Returns middleware for multiple files per field, grouped by field name.
374
+
375
+ ```javascript
376
+ target.register('/upload', upload.files('photos', 'documents'), handler);
377
+ ```
378
+
379
+ ### Uploaded File Object
380
+
381
+ ```javascript
382
+ {
383
+ filename: string, // Original filename
384
+ extension: string, // File extension
385
+ path: {
386
+ absolute: string, // Absolute path on disk
387
+ relative: string // Relative to cwd
388
+ },
389
+ mimetype: string, // MIME type
390
+ size: {
391
+ value: number, // Numeric size value
392
+ symbol: string // Unit: 'B', 'KB', 'MB', etc.
393
+ }
394
+ }
395
+ ```
396
+
397
+ ---
398
+
399
+ ## Utility Functions
400
+
401
+ ### listAllEndpoints(grouped)
402
+
403
+ Get all registered endpoints.
404
+
405
+ ```javascript
406
+ import { listAllEndpoints } from 'te.js';
407
+
408
+ const routes = listAllEndpoints(); // ['/', '/users', '/api/data']
409
+ const grouped = listAllEndpoints(true); // { users: [...], api: [...] }
410
+ ```
411
+
412
+ | Parameter | Type | Default | Description |
413
+ |-----------|------|---------|-------------|
414
+ | `grouped` | boolean | `false` | Group by first path segment |
415
+
416
+ ---
417
+
418
+ ## Middleware Signatures
419
+
420
+ Tejas detects the middleware style by argument count:
421
+
422
+ ### Tejas Style (2 arguments)
423
+
424
+ ```javascript
425
+ const middleware = (ammo, next) => {
426
+ // Access ammo properties
427
+ next();
428
+ };
429
+ ```
430
+
431
+ ### Express Style (3 arguments)
432
+
433
+ ```javascript
434
+ const middleware = (req, res, next) => {
435
+ // Access req, res directly
436
+ next();
437
+ };
438
+ ```
439
+
440
+ ---
441
+
442
+ ## Environment Access
443
+
444
+ ```javascript
445
+ import { env, setEnv } from 'tej-env';
446
+
447
+ const port = env('PORT');
448
+ setEnv('CUSTOM_VAR', 'value');
449
+ ```
450
+
451
+ ---
452
+
453
+ ## Database Manager
454
+
455
+ ```javascript
456
+ import dbManager from 'te.js/database/index.js';
457
+
458
+ // Get connection
459
+ const redis = dbManager.getConnection('redis');
460
+ const mongo = dbManager.getConnection('mongodb');
461
+
462
+ // Check connection status
463
+ const status = dbManager.hasConnection('redis', {});
464
+ // { exists: boolean, initializing: boolean }
465
+
466
+ // Close connections
467
+ await dbManager.closeConnection('redis');
468
+ await dbManager.closeAllConnections();
469
+
470
+ // Get all active connections
471
+ const connections = dbManager.getActiveConnections();
472
+ // Returns: Map
473
+ ```
474
+
475
+ ---
476
+
477
+ ## RateLimitStorage Base Class
478
+
479
+ Abstract base class for custom rate limit storage backends:
480
+
481
+ ```javascript
482
+ import RateLimitStorage from 'te.js/rate-limit/storage/base.js';
483
+
484
+ class CustomStorage extends RateLimitStorage {
485
+ async get(key) { } // Return object or null
486
+ async set(key, value, ttl) { } // Store with TTL (seconds)
487
+ async increment(key) { } // Return new value or null
488
+ async delete(key) { } // Remove key
489
+ }
490
+ ```