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.
- package/README.md +197 -196
- package/auto-docs/analysis/handler-analyzer.js +58 -58
- package/auto-docs/analysis/source-resolver.js +101 -101
- package/auto-docs/constants.js +37 -37
- package/auto-docs/docs-llm/index.js +7 -7
- package/auto-docs/docs-llm/prompts.js +222 -222
- package/auto-docs/docs-llm/provider.js +132 -132
- package/auto-docs/index.js +146 -146
- package/auto-docs/openapi/endpoint-processor.js +277 -277
- package/auto-docs/openapi/generator.js +107 -107
- package/auto-docs/openapi/level3.js +131 -131
- package/auto-docs/openapi/spec-builders.js +244 -244
- package/auto-docs/ui/docs-ui.js +186 -186
- package/auto-docs/utils/logger.js +17 -17
- package/auto-docs/utils/strip-usage.js +10 -10
- package/cli/docs-command.js +315 -315
- package/cli/fly-command.js +71 -71
- package/cli/index.js +56 -56
- package/cors/index.js +71 -0
- package/database/index.js +165 -165
- package/database/mongodb.js +146 -146
- package/database/redis.js +201 -201
- package/docs/README.md +36 -36
- package/docs/ammo.md +362 -362
- package/docs/api-reference.md +490 -490
- package/docs/auto-docs.md +216 -216
- package/docs/cli.md +152 -152
- package/docs/configuration.md +275 -275
- package/docs/database.md +390 -390
- package/docs/error-handling.md +438 -438
- package/docs/file-uploads.md +333 -333
- package/docs/getting-started.md +214 -214
- package/docs/middleware.md +355 -355
- package/docs/rate-limiting.md +393 -393
- package/docs/routing.md +302 -302
- package/lib/llm/client.js +73 -0
- package/lib/llm/index.js +7 -0
- package/lib/llm/parse.js +89 -0
- package/package.json +64 -62
- package/rate-limit/algorithms/fixed-window.js +141 -141
- package/rate-limit/algorithms/sliding-window.js +147 -147
- package/rate-limit/algorithms/token-bucket.js +115 -115
- package/rate-limit/base.js +165 -165
- package/rate-limit/index.js +147 -147
- package/rate-limit/storage/base.js +104 -104
- package/rate-limit/storage/memory.js +101 -101
- package/rate-limit/storage/redis.js +88 -88
- package/server/ammo/body-parser.js +220 -220
- package/server/ammo/dispatch-helper.js +103 -103
- package/server/ammo/enhancer.js +57 -57
- package/server/ammo.js +454 -415
- package/server/endpoint.js +97 -74
- package/server/error.js +9 -9
- package/server/errors/code-context.js +125 -125
- package/server/errors/llm-error-service.js +140 -140
- package/server/files/helper.js +33 -33
- package/server/files/uploader.js +143 -143
- package/server/handler.js +158 -119
- package/server/target.js +185 -175
- package/server/targets/middleware-validator.js +22 -22
- package/server/targets/path-validator.js +21 -21
- package/server/targets/registry.js +160 -160
- package/server/targets/shoot-validator.js +21 -21
- package/te.js +428 -402
- package/utils/auto-register.js +17 -17
- package/utils/configuration.js +64 -64
- package/utils/errors-llm-config.js +84 -84
- package/utils/request-logger.js +43 -43
- package/utils/status-codes.js +82 -82
- package/utils/tejas-entrypoint-html.js +18 -18
package/docs/api-reference.md
CHANGED
|
@@ -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
|
+
```
|