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.
Files changed (80) hide show
  1. package/.cursor/plans/ai_native_framework_features_5bb1a20a.plan.md +234 -0
  2. package/.cursor/plans/auto_error_fix_agent_e68979c5.plan.md +356 -0
  3. package/.cursor/plans/tejas_framework_test_suite_5e3c6fad.plan.md +168 -0
  4. package/.prettierignore +31 -0
  5. package/README.md +156 -14
  6. package/auto-docs/analysis/handler-analyzer.js +58 -0
  7. package/auto-docs/analysis/source-resolver.js +101 -0
  8. package/auto-docs/constants.js +37 -0
  9. package/auto-docs/index.js +146 -0
  10. package/auto-docs/llm/index.js +6 -0
  11. package/auto-docs/llm/parse.js +88 -0
  12. package/auto-docs/llm/prompts.js +222 -0
  13. package/auto-docs/llm/provider.js +187 -0
  14. package/auto-docs/openapi/endpoint-processor.js +277 -0
  15. package/auto-docs/openapi/generator.js +107 -0
  16. package/auto-docs/openapi/level3.js +131 -0
  17. package/auto-docs/openapi/spec-builders.js +244 -0
  18. package/auto-docs/ui/docs-ui.js +186 -0
  19. package/auto-docs/utils/logger.js +17 -0
  20. package/auto-docs/utils/strip-usage.js +10 -0
  21. package/cli/docs-command.js +315 -0
  22. package/cli/fly-command.js +71 -0
  23. package/cli/index.js +57 -0
  24. package/database/index.js +163 -5
  25. package/database/mongodb.js +146 -0
  26. package/database/redis.js +201 -0
  27. package/docs/README.md +36 -0
  28. package/docs/ammo.md +362 -0
  29. package/docs/api-reference.md +489 -0
  30. package/docs/auto-docs.md +215 -0
  31. package/docs/cli.md +152 -0
  32. package/docs/configuration.md +233 -0
  33. package/docs/database.md +391 -0
  34. package/docs/error-handling.md +417 -0
  35. package/docs/file-uploads.md +334 -0
  36. package/docs/getting-started.md +181 -0
  37. package/docs/middleware.md +356 -0
  38. package/docs/rate-limiting.md +394 -0
  39. package/docs/routing.md +302 -0
  40. package/example/API_OVERVIEW.md +77 -0
  41. package/example/README.md +155 -0
  42. package/example/index.js +27 -2
  43. package/example/openapi.json +390 -0
  44. package/example/package.json +5 -2
  45. package/example/services/cache.service.js +25 -0
  46. package/example/services/user.service.js +42 -0
  47. package/example/start-redis.js +2 -0
  48. package/example/targets/cache.target.js +35 -0
  49. package/example/targets/index.target.js +11 -2
  50. package/example/targets/users.target.js +60 -0
  51. package/example/tejas.config.json +13 -1
  52. package/package.json +20 -5
  53. package/rate-limit/algorithms/fixed-window.js +141 -0
  54. package/rate-limit/algorithms/sliding-window.js +147 -0
  55. package/rate-limit/algorithms/token-bucket.js +115 -0
  56. package/rate-limit/base.js +165 -0
  57. package/rate-limit/index.js +147 -0
  58. package/rate-limit/storage/base.js +104 -0
  59. package/rate-limit/storage/memory.js +102 -0
  60. package/rate-limit/storage/redis.js +88 -0
  61. package/server/ammo/body-parser.js +152 -25
  62. package/server/ammo/enhancer.js +6 -2
  63. package/server/ammo.js +356 -327
  64. package/server/endpoint.js +21 -0
  65. package/server/handler.js +113 -87
  66. package/server/target.js +50 -9
  67. package/server/targets/registry.js +111 -6
  68. package/te.js +363 -137
  69. package/tests/auto-docs/handler-analyzer.test.js +44 -0
  70. package/tests/auto-docs/openapi-generator.test.js +103 -0
  71. package/tests/auto-docs/parse.test.js +63 -0
  72. package/tests/auto-docs/source-resolver.test.js +58 -0
  73. package/tests/helpers/index.js +37 -0
  74. package/tests/helpers/mock-http.js +342 -0
  75. package/tests/helpers/test-utils.js +446 -0
  76. package/tests/setup.test.js +148 -0
  77. package/utils/configuration.js +13 -10
  78. package/vitest.config.js +54 -0
  79. package/database/mongo.js +0 -67
  80. 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