te.js 1.3.0 → 2.0.0
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/.cursor/plans/ai_native_framework_features_5bb1a20a.plan.md +234 -0
- package/.cursor/plans/auto_error_fix_agent_e68979c5.plan.md +356 -0
- package/.cursor/plans/tejas_framework_test_suite_5e3c6fad.plan.md +168 -0
- package/.prettierignore +31 -0
- package/README.md +156 -14
- package/auto-docs/analysis/handler-analyzer.js +58 -0
- package/auto-docs/analysis/source-resolver.js +101 -0
- package/auto-docs/constants.js +37 -0
- package/auto-docs/index.js +146 -0
- package/auto-docs/llm/index.js +6 -0
- package/auto-docs/llm/parse.js +88 -0
- package/auto-docs/llm/prompts.js +222 -0
- package/auto-docs/llm/provider.js +187 -0
- package/auto-docs/openapi/endpoint-processor.js +277 -0
- package/auto-docs/openapi/generator.js +107 -0
- package/auto-docs/openapi/level3.js +131 -0
- package/auto-docs/openapi/spec-builders.js +244 -0
- package/auto-docs/ui/docs-ui.js +186 -0
- package/auto-docs/utils/logger.js +17 -0
- package/auto-docs/utils/strip-usage.js +10 -0
- package/cli/docs-command.js +315 -0
- package/cli/fly-command.js +71 -0
- package/cli/index.js +57 -0
- package/database/index.js +163 -5
- package/database/mongodb.js +146 -0
- package/database/redis.js +201 -0
- package/docs/README.md +36 -0
- package/docs/ammo.md +362 -0
- package/docs/api-reference.md +489 -0
- package/docs/auto-docs.md +215 -0
- package/docs/cli.md +152 -0
- package/docs/configuration.md +233 -0
- package/docs/database.md +391 -0
- package/docs/error-handling.md +417 -0
- package/docs/file-uploads.md +334 -0
- package/docs/getting-started.md +181 -0
- package/docs/middleware.md +356 -0
- package/docs/rate-limiting.md +394 -0
- package/docs/routing.md +302 -0
- package/example/API_OVERVIEW.md +77 -0
- package/example/README.md +155 -0
- package/example/index.js +27 -2
- package/example/openapi.json +390 -0
- package/example/package.json +5 -2
- package/example/services/cache.service.js +25 -0
- package/example/services/user.service.js +42 -0
- package/example/start-redis.js +2 -0
- package/example/targets/cache.target.js +35 -0
- package/example/targets/index.target.js +11 -2
- package/example/targets/users.target.js +60 -0
- package/example/tejas.config.json +13 -1
- package/package.json +20 -5
- package/rate-limit/algorithms/fixed-window.js +141 -0
- package/rate-limit/algorithms/sliding-window.js +147 -0
- package/rate-limit/algorithms/token-bucket.js +115 -0
- package/rate-limit/base.js +165 -0
- package/rate-limit/index.js +147 -0
- package/rate-limit/storage/base.js +104 -0
- package/rate-limit/storage/memory.js +102 -0
- package/rate-limit/storage/redis.js +88 -0
- package/server/ammo/body-parser.js +152 -25
- package/server/ammo/enhancer.js +6 -2
- package/server/ammo.js +356 -327
- package/server/endpoint.js +21 -0
- package/server/handler.js +113 -87
- package/server/target.js +50 -9
- package/server/targets/registry.js +111 -6
- package/te.js +363 -137
- package/tests/auto-docs/handler-analyzer.test.js +44 -0
- package/tests/auto-docs/openapi-generator.test.js +103 -0
- package/tests/auto-docs/parse.test.js +63 -0
- package/tests/auto-docs/source-resolver.test.js +58 -0
- package/tests/helpers/index.js +37 -0
- package/tests/helpers/mock-http.js +342 -0
- package/tests/helpers/test-utils.js +446 -0
- package/tests/setup.test.js +148 -0
- package/utils/configuration.js +13 -10
- package/vitest.config.js +54 -0
- package/database/mongo.js +0 -67
- package/example/targets/user/user.target.js +0 -17
|
@@ -0,0 +1,489 @@
|
|
|
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.
|
|
267
|
+
|
|
268
|
+
| Signature | Behavior |
|
|
269
|
+
|-----------|----------|
|
|
270
|
+
| `throw()` | 500 "Internal Server Error" |
|
|
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 |
|
|
275
|
+
|
|
276
|
+
#### redirect(url, statusCode)
|
|
277
|
+
|
|
278
|
+
HTTP redirect.
|
|
279
|
+
|
|
280
|
+
```javascript
|
|
281
|
+
ammo.redirect('/new-path'); // 302 temporary
|
|
282
|
+
ammo.redirect('/new-path', 301); // 301 permanent
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
| Parameter | Type | Default | Description |
|
|
286
|
+
|-----------|------|---------|-------------|
|
|
287
|
+
| `url` | string | — | Redirect URL |
|
|
288
|
+
| `statusCode` | number | `302` | HTTP status code |
|
|
289
|
+
|
|
290
|
+
#### notFound()
|
|
291
|
+
|
|
292
|
+
Throws 404 Not Found.
|
|
293
|
+
|
|
294
|
+
#### notAllowed()
|
|
295
|
+
|
|
296
|
+
Throws 405 Method Not Allowed.
|
|
297
|
+
|
|
298
|
+
#### unauthorized()
|
|
299
|
+
|
|
300
|
+
Throws 401 Unauthorized.
|
|
301
|
+
|
|
302
|
+
#### defaultEntry()
|
|
303
|
+
|
|
304
|
+
Sends the default Tejas HTML entry page. Used internally for the root `/` route when no target matches.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## TejError Class
|
|
309
|
+
|
|
310
|
+
Custom error class for HTTP errors.
|
|
311
|
+
|
|
312
|
+
```javascript
|
|
313
|
+
import { TejError } from 'te.js';
|
|
314
|
+
|
|
315
|
+
throw new TejError(statusCode, message);
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
| Parameter | Type | Description |
|
|
319
|
+
|-----------|------|-------------|
|
|
320
|
+
| `statusCode` | number | HTTP status code |
|
|
321
|
+
| `message` | string | Error message |
|
|
322
|
+
|
|
323
|
+
| Property | Type | Description |
|
|
324
|
+
|----------|------|-------------|
|
|
325
|
+
| `code` | number | HTTP status code |
|
|
326
|
+
| `message` | string | Error message |
|
|
327
|
+
| `name` | string | `'TejError'` |
|
|
328
|
+
|
|
329
|
+
### BodyParserError
|
|
330
|
+
|
|
331
|
+
A subclass of `TejError` thrown during request body parsing:
|
|
332
|
+
|
|
333
|
+
| Status | Condition |
|
|
334
|
+
|--------|-----------|
|
|
335
|
+
| 400 | Malformed JSON, invalid URL-encoded data, or corrupted multipart data |
|
|
336
|
+
| 408 | Body parsing timed out |
|
|
337
|
+
| 413 | Request body exceeds `body.max_size` |
|
|
338
|
+
| 415 | Unsupported content type |
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## TejFileUploader Class
|
|
343
|
+
|
|
344
|
+
File upload handler as middleware.
|
|
345
|
+
|
|
346
|
+
### Constructor
|
|
347
|
+
|
|
348
|
+
```javascript
|
|
349
|
+
import { TejFileUploader } from 'te.js';
|
|
350
|
+
|
|
351
|
+
const upload = new TejFileUploader(options);
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
| Option | Type | Description |
|
|
355
|
+
|--------|------|-------------|
|
|
356
|
+
| `destination` | string | Directory to save uploaded files |
|
|
357
|
+
| `name` | string | Optional custom filename |
|
|
358
|
+
| `maxFileSize` | number | Max file size in bytes (throws 413 if exceeded) |
|
|
359
|
+
|
|
360
|
+
### Methods
|
|
361
|
+
|
|
362
|
+
#### file(...fieldNames)
|
|
363
|
+
|
|
364
|
+
Returns middleware for single file upload per field.
|
|
365
|
+
|
|
366
|
+
```javascript
|
|
367
|
+
target.register('/upload', upload.file('avatar'), handler);
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
#### files(...fieldNames)
|
|
371
|
+
|
|
372
|
+
Returns middleware for multiple files per field, grouped by field name.
|
|
373
|
+
|
|
374
|
+
```javascript
|
|
375
|
+
target.register('/upload', upload.files('photos', 'documents'), handler);
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Uploaded File Object
|
|
379
|
+
|
|
380
|
+
```javascript
|
|
381
|
+
{
|
|
382
|
+
filename: string, // Original filename
|
|
383
|
+
extension: string, // File extension
|
|
384
|
+
path: {
|
|
385
|
+
absolute: string, // Absolute path on disk
|
|
386
|
+
relative: string // Relative to cwd
|
|
387
|
+
},
|
|
388
|
+
mimetype: string, // MIME type
|
|
389
|
+
size: {
|
|
390
|
+
value: number, // Numeric size value
|
|
391
|
+
symbol: string // Unit: 'B', 'KB', 'MB', etc.
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Utility Functions
|
|
399
|
+
|
|
400
|
+
### listAllEndpoints(grouped)
|
|
401
|
+
|
|
402
|
+
Get all registered endpoints.
|
|
403
|
+
|
|
404
|
+
```javascript
|
|
405
|
+
import { listAllEndpoints } from 'te.js';
|
|
406
|
+
|
|
407
|
+
const routes = listAllEndpoints(); // ['/', '/users', '/api/data']
|
|
408
|
+
const grouped = listAllEndpoints(true); // { users: [...], api: [...] }
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
| Parameter | Type | Default | Description |
|
|
412
|
+
|-----------|------|---------|-------------|
|
|
413
|
+
| `grouped` | boolean | `false` | Group by first path segment |
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
## Middleware Signatures
|
|
418
|
+
|
|
419
|
+
Tejas detects the middleware style by argument count:
|
|
420
|
+
|
|
421
|
+
### Tejas Style (2 arguments)
|
|
422
|
+
|
|
423
|
+
```javascript
|
|
424
|
+
const middleware = (ammo, next) => {
|
|
425
|
+
// Access ammo properties
|
|
426
|
+
next();
|
|
427
|
+
};
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Express Style (3 arguments)
|
|
431
|
+
|
|
432
|
+
```javascript
|
|
433
|
+
const middleware = (req, res, next) => {
|
|
434
|
+
// Access req, res directly
|
|
435
|
+
next();
|
|
436
|
+
};
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Environment Access
|
|
442
|
+
|
|
443
|
+
```javascript
|
|
444
|
+
import { env, setEnv } from 'tej-env';
|
|
445
|
+
|
|
446
|
+
const port = env('PORT');
|
|
447
|
+
setEnv('CUSTOM_VAR', 'value');
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## Database Manager
|
|
453
|
+
|
|
454
|
+
```javascript
|
|
455
|
+
import dbManager from 'te.js/database/index.js';
|
|
456
|
+
|
|
457
|
+
// Get connection
|
|
458
|
+
const redis = dbManager.getConnection('redis');
|
|
459
|
+
const mongo = dbManager.getConnection('mongodb');
|
|
460
|
+
|
|
461
|
+
// Check connection status
|
|
462
|
+
const status = dbManager.hasConnection('redis', {});
|
|
463
|
+
// { exists: boolean, initializing: boolean }
|
|
464
|
+
|
|
465
|
+
// Close connections
|
|
466
|
+
await dbManager.closeConnection('redis');
|
|
467
|
+
await dbManager.closeAllConnections();
|
|
468
|
+
|
|
469
|
+
// Get all active connections
|
|
470
|
+
const connections = dbManager.getActiveConnections();
|
|
471
|
+
// Returns: Map
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## RateLimitStorage Base Class
|
|
477
|
+
|
|
478
|
+
Abstract base class for custom rate limit storage backends:
|
|
479
|
+
|
|
480
|
+
```javascript
|
|
481
|
+
import RateLimitStorage from 'te.js/rate-limit/storage/base.js';
|
|
482
|
+
|
|
483
|
+
class CustomStorage extends RateLimitStorage {
|
|
484
|
+
async get(key) { } // Return object or null
|
|
485
|
+
async set(key, value, ttl) { } // Store with TTL (seconds)
|
|
486
|
+
async increment(key) { } // Return new value or null
|
|
487
|
+
async delete(key) { } // Remove key
|
|
488
|
+
}
|
|
489
|
+
```
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Auto-Documentation
|
|
2
|
+
|
|
3
|
+
Tejas can automatically generate an OpenAPI 3.0 specification from your registered targets. An LLM analyzes your handler source code to produce accurate summaries, request/response schemas, and descriptions — then you can serve interactive API docs with a single line of code.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Generate an OpenAPI spec interactively
|
|
9
|
+
npx tejas generate:docs
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```javascript
|
|
13
|
+
// Serve the generated docs in your app
|
|
14
|
+
app.serveDocs({ specPath: './openapi.json' });
|
|
15
|
+
app.takeoff();
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Visit `http://localhost:1403/docs` to see the interactive Scalar API reference.
|
|
19
|
+
|
|
20
|
+
## How It Works
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Target files → Handler analysis → LLM enhancement → OpenAPI 3.0 spec → Scalar UI
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
1. **Handler analysis** — Tejas reads each handler's source code and detects which HTTP methods it handles (`ammo.GET`, `ammo.POST`, etc.). Handlers without method checks are treated as accepting all methods.
|
|
27
|
+
2. **LLM enhancement** — The handler source (and optionally its dependencies) is sent to an LLM, which generates summaries, parameter descriptions, request/response schemas, and tags.
|
|
28
|
+
3. **Spec generation** — Results are assembled into a valid OpenAPI 3.0 document.
|
|
29
|
+
4. **Optional level-3 post-processing** — Tags are reordered by importance and an `API_OVERVIEW.md` page is generated.
|
|
30
|
+
|
|
31
|
+
## Enhancement Levels
|
|
32
|
+
|
|
33
|
+
The `level` option controls how much context the LLM receives and how much work it does:
|
|
34
|
+
|
|
35
|
+
| Level | Name | Context Sent to LLM | Output |
|
|
36
|
+
|-------|------|---------------------|--------|
|
|
37
|
+
| **1** | Moderate | Handler source code only (~hundreds of tokens per endpoint) | Summaries, schemas, tags |
|
|
38
|
+
| **2** | High | Handler + full dependency chain from imports (~thousands of tokens per endpoint) | More accurate schemas and descriptions |
|
|
39
|
+
| **3** | Comprehensive | Same as level 2, plus post-processing | Everything from level 2, plus: reordered tags by importance, `API_OVERVIEW.md` page |
|
|
40
|
+
|
|
41
|
+
Higher levels produce better documentation but use more LLM tokens.
|
|
42
|
+
|
|
43
|
+
## Endpoint Metadata
|
|
44
|
+
|
|
45
|
+
You can provide explicit metadata when registering endpoints. This metadata is used directly in the OpenAPI spec and takes priority over LLM-generated content:
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
const users = new Target('/users');
|
|
49
|
+
|
|
50
|
+
users.register('/', {
|
|
51
|
+
summary: 'User operations',
|
|
52
|
+
description: 'Create and list users',
|
|
53
|
+
methods: ['GET', 'POST'],
|
|
54
|
+
request: {
|
|
55
|
+
name: { type: 'string', required: true },
|
|
56
|
+
email: { type: 'string', required: true }
|
|
57
|
+
},
|
|
58
|
+
response: {
|
|
59
|
+
200: { description: 'Success' },
|
|
60
|
+
201: { description: 'User created' },
|
|
61
|
+
400: { description: 'Validation error' }
|
|
62
|
+
}
|
|
63
|
+
}, (ammo) => {
|
|
64
|
+
if (ammo.GET) return ammo.fire(userService.list());
|
|
65
|
+
if (ammo.POST) return ammo.fire(201, userService.create(ammo.payload));
|
|
66
|
+
ammo.notAllowed();
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The metadata object is optional. When omitted, the LLM infers everything from the handler source.
|
|
71
|
+
|
|
72
|
+
## LLM Provider Configuration
|
|
73
|
+
|
|
74
|
+
Tejas uses an OpenAI-compatible API for LLM calls. This works with OpenAI, OpenRouter, Ollama, and any provider that implements the OpenAI chat completions endpoint.
|
|
75
|
+
|
|
76
|
+
### Via `tejas.config.json`
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"docs": {
|
|
81
|
+
"llm": {
|
|
82
|
+
"baseURL": "https://api.openai.com/v1",
|
|
83
|
+
"apiKey": "sk-...",
|
|
84
|
+
"model": "gpt-4o-mini"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Via Environment Variables
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
LLM_BASE_URL=https://api.openai.com/v1
|
|
94
|
+
LLM_API_KEY=sk-...
|
|
95
|
+
LLM_MODEL=gpt-4o-mini
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Using Ollama (Local)
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"docs": {
|
|
103
|
+
"llm": {
|
|
104
|
+
"baseURL": "http://localhost:11434/v1",
|
|
105
|
+
"model": "llama3"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
No API key is required for local providers.
|
|
112
|
+
|
|
113
|
+
## Configuration Reference
|
|
114
|
+
|
|
115
|
+
All options live under the `docs` key in `tejas.config.json`:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"docs": {
|
|
120
|
+
"dirTargets": "targets",
|
|
121
|
+
"output": "./openapi.json",
|
|
122
|
+
"title": "My API",
|
|
123
|
+
"version": "1.0.0",
|
|
124
|
+
"description": "API description",
|
|
125
|
+
"level": 1,
|
|
126
|
+
"llm": {
|
|
127
|
+
"baseURL": "https://api.openai.com/v1",
|
|
128
|
+
"apiKey": "sk-...",
|
|
129
|
+
"model": "gpt-4o-mini"
|
|
130
|
+
},
|
|
131
|
+
"overviewPath": "./API_OVERVIEW.md",
|
|
132
|
+
"productionBranch": "main"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
| Key | Type | Default | Description |
|
|
138
|
+
|-----|------|---------|-------------|
|
|
139
|
+
| `dirTargets` | string | `"targets"` | Directory containing `.target.js` files |
|
|
140
|
+
| `output` | string | `"./openapi.json"` | Output file path for the generated spec |
|
|
141
|
+
| `title` | string | `"API"` | API title in the OpenAPI `info` block |
|
|
142
|
+
| `version` | string | `"1.0.0"` | API version in the OpenAPI `info` block |
|
|
143
|
+
| `description` | string | `""` | API description |
|
|
144
|
+
| `level` | number | `1` | Enhancement level (1–3) |
|
|
145
|
+
| `llm` | object | — | LLM provider configuration (see above) |
|
|
146
|
+
| `overviewPath` | string | `"./API_OVERVIEW.md"` | Path for the generated overview page (level 3 only) |
|
|
147
|
+
| `productionBranch` | string | `"main"` | Branch that triggers `docs:on-push` |
|
|
148
|
+
|
|
149
|
+
## Serving API Docs
|
|
150
|
+
|
|
151
|
+
Use `serveDocs()` to serve an interactive [Scalar](https://scalar.com) API reference UI:
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
import Tejas from 'te.js';
|
|
155
|
+
|
|
156
|
+
const app = new Tejas();
|
|
157
|
+
|
|
158
|
+
app.serveDocs({ specPath: './openapi.json' });
|
|
159
|
+
|
|
160
|
+
app.takeoff();
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
This registers two routes:
|
|
164
|
+
|
|
165
|
+
| Route | Description |
|
|
166
|
+
|-------|-------------|
|
|
167
|
+
| `GET /docs` | Interactive Scalar API reference UI |
|
|
168
|
+
| `GET /docs/openapi.json` | Raw OpenAPI spec JSON |
|
|
169
|
+
|
|
170
|
+
### serveDocs Options
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
app.serveDocs({
|
|
174
|
+
specPath: './openapi.json', // Path to the spec file (relative to cwd)
|
|
175
|
+
scalarConfig: { // Scalar UI configuration
|
|
176
|
+
layout: 'modern', // 'modern' or 'classic'
|
|
177
|
+
theme: 'default',
|
|
178
|
+
showSidebar: true,
|
|
179
|
+
hideTestRequestButton: false
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
See the [Scalar configuration reference](https://scalar.com/products/api-references/configuration) for all available UI options.
|
|
185
|
+
|
|
186
|
+
## CLI Commands
|
|
187
|
+
|
|
188
|
+
| Command | Description |
|
|
189
|
+
|---------|-------------|
|
|
190
|
+
| `tejas generate:docs` | Interactive OpenAPI generation |
|
|
191
|
+
| `tejas generate:docs --ci` | Non-interactive mode (for CI/CD) |
|
|
192
|
+
| `tejas docs:on-push` | Generate docs when pushing to production branch |
|
|
193
|
+
|
|
194
|
+
See the [CLI Reference](./cli.md) for full details.
|
|
195
|
+
|
|
196
|
+
## Workflow Example
|
|
197
|
+
|
|
198
|
+
A typical workflow for maintaining API docs:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# 1. Generate docs during development
|
|
202
|
+
npx tejas generate:docs
|
|
203
|
+
|
|
204
|
+
# 2. Serve docs in your app
|
|
205
|
+
# (add app.serveDocs({ specPath: './openapi.json' }) to your entry file)
|
|
206
|
+
|
|
207
|
+
# 3. Auto-regenerate on push to main
|
|
208
|
+
# (add tejas docs:on-push to your pre-push hook)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Next Steps
|
|
212
|
+
|
|
213
|
+
- [CLI Reference](./cli.md) — Detailed CLI command documentation
|
|
214
|
+
- [Configuration](./configuration.md) — Full framework configuration reference
|
|
215
|
+
- [Routing](./routing.md) — Learn about endpoint metadata
|