te.js 2.0.3 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +197 -187
  2. package/auto-docs/analysis/handler-analyzer.js +58 -58
  3. package/auto-docs/analysis/source-resolver.js +101 -101
  4. package/auto-docs/constants.js +37 -37
  5. package/auto-docs/docs-llm/index.js +7 -0
  6. package/auto-docs/{llm → docs-llm}/prompts.js +222 -222
  7. package/auto-docs/{llm → docs-llm}/provider.js +132 -187
  8. package/auto-docs/index.js +146 -146
  9. package/auto-docs/openapi/endpoint-processor.js +277 -277
  10. package/auto-docs/openapi/generator.js +107 -107
  11. package/auto-docs/openapi/level3.js +131 -131
  12. package/auto-docs/openapi/spec-builders.js +244 -244
  13. package/auto-docs/ui/docs-ui.js +186 -186
  14. package/auto-docs/utils/logger.js +17 -17
  15. package/auto-docs/utils/strip-usage.js +10 -10
  16. package/cli/docs-command.js +315 -315
  17. package/cli/fly-command.js +71 -71
  18. package/cli/index.js +56 -56
  19. package/database/index.js +165 -165
  20. package/database/mongodb.js +146 -146
  21. package/database/redis.js +201 -201
  22. package/docs/README.md +36 -36
  23. package/docs/ammo.md +362 -362
  24. package/docs/api-reference.md +490 -489
  25. package/docs/auto-docs.md +216 -215
  26. package/docs/cli.md +152 -152
  27. package/docs/configuration.md +275 -233
  28. package/docs/database.md +390 -391
  29. package/docs/error-handling.md +438 -417
  30. package/docs/file-uploads.md +333 -334
  31. package/docs/getting-started.md +214 -215
  32. package/docs/middleware.md +355 -356
  33. package/docs/rate-limiting.md +393 -394
  34. package/docs/routing.md +302 -302
  35. package/package.json +62 -62
  36. package/rate-limit/algorithms/fixed-window.js +141 -141
  37. package/rate-limit/algorithms/sliding-window.js +147 -147
  38. package/rate-limit/algorithms/token-bucket.js +115 -115
  39. package/rate-limit/base.js +165 -165
  40. package/rate-limit/index.js +147 -147
  41. package/rate-limit/storage/base.js +104 -104
  42. package/rate-limit/storage/memory.js +101 -101
  43. package/rate-limit/storage/redis.js +88 -88
  44. package/server/ammo/body-parser.js +220 -220
  45. package/server/ammo/dispatch-helper.js +103 -103
  46. package/server/ammo/enhancer.js +57 -57
  47. package/server/ammo.js +454 -356
  48. package/server/endpoint.js +97 -74
  49. package/server/error.js +9 -9
  50. package/server/errors/code-context.js +125 -0
  51. package/server/errors/llm-error-service.js +140 -0
  52. package/server/files/helper.js +33 -33
  53. package/server/files/uploader.js +143 -143
  54. package/server/handler.js +158 -113
  55. package/server/target.js +185 -175
  56. package/server/targets/middleware-validator.js +22 -22
  57. package/server/targets/path-validator.js +21 -21
  58. package/server/targets/registry.js +160 -160
  59. package/server/targets/shoot-validator.js +21 -21
  60. package/te.js +428 -363
  61. package/utils/auto-register.js +17 -17
  62. package/utils/configuration.js +64 -64
  63. package/utils/errors-llm-config.js +84 -0
  64. package/utils/request-logger.js +43 -43
  65. package/utils/status-codes.js +82 -82
  66. package/utils/tejas-entrypoint-html.js +18 -18
  67. package/auto-docs/llm/index.js +0 -6
  68. package/auto-docs/llm/parse.js +0 -88
package/docs/routing.md CHANGED
@@ -1,302 +1,302 @@
1
- # Routing with Targets
2
-
3
- Tejas uses a **Target-based** routing system. A Target is similar to an Express Router—it groups related endpoints under a common base path.
4
-
5
- ## Creating a Target
6
-
7
- ```javascript
8
- import { Target } from 'te.js';
9
-
10
- const target = new Target('/api');
11
- ```
12
-
13
- ## Registering Endpoints
14
-
15
- Use `register()` to add endpoints to a target:
16
-
17
- ```javascript
18
- target.register('/users', (ammo) => {
19
- ammo.fire([{ id: 1, name: 'John' }]);
20
- });
21
- ```
22
-
23
- This creates a route at `GET /api/users`.
24
-
25
- ## Method Handling
26
-
27
- Tejas routes are **method-agnostic** by default. Use the method flags on `ammo` to handle different HTTP methods:
28
-
29
- ```javascript
30
- target.register('/users', (ammo) => {
31
- if (ammo.GET) {
32
- // Handle GET /api/users
33
- ammo.fire([{ id: 1, name: 'John' }]);
34
- } else if (ammo.POST) {
35
- // Handle POST /api/users
36
- const { name, email } = ammo.payload;
37
- ammo.fire(201, { id: 2, name, email });
38
- } else {
39
- ammo.notAllowed();
40
- }
41
- });
42
- ```
43
-
44
- ### Available Method Flags
45
-
46
- - `ammo.GET`
47
- - `ammo.POST`
48
- - `ammo.PUT`
49
- - `ammo.DELETE`
50
- - `ammo.PATCH`
51
- - `ammo.HEAD`
52
- - `ammo.OPTIONS`
53
-
54
- ## Parameterized Routes
55
-
56
- Use `:param` syntax for dynamic route segments:
57
-
58
- ```javascript
59
- target.register('/users/:id', (ammo) => {
60
- const { id } = ammo.payload;
61
- ammo.fire({ userId: id });
62
- });
63
-
64
- target.register('/users/:userId/posts/:postId', (ammo) => {
65
- const { userId, postId } = ammo.payload;
66
- ammo.fire({ userId, postId });
67
- });
68
- ```
69
-
70
- Route parameters are automatically extracted and added to `ammo.payload`.
71
-
72
- ## Query Parameters
73
-
74
- Query parameters are also available in `ammo.payload`:
75
-
76
- ```javascript
77
- // Request: GET /api/users?page=2&limit=10
78
-
79
- target.register('/users', (ammo) => {
80
- const { page, limit } = ammo.payload;
81
- ammo.fire({ page, limit }); // { page: "2", limit: "10" }
82
- });
83
- ```
84
-
85
- ## Route Priority
86
-
87
- Routes are matched in the following order:
88
-
89
- 1. **Exact matches** (most specific)
90
- 2. **Parameterized routes** (in registration order)
91
-
92
- ```javascript
93
- // These don't conflict:
94
- target.register('/users/me', handler); // Exact match for /users/me
95
- target.register('/users/:id', handler); // Matches /users/123, /users/john
96
- ```
97
-
98
- ## Target-Level Middleware
99
-
100
- Apply middleware to all routes in a target:
101
-
102
- ```javascript
103
- const api = new Target('/api');
104
-
105
- // This middleware runs for ALL /api/* routes
106
- api.midair((ammo, next) => {
107
- console.log('API request:', ammo.path);
108
- next();
109
- });
110
-
111
- api.register('/users', handler);
112
- api.register('/posts', handler);
113
- ```
114
-
115
- ## Route-Specific Middleware
116
-
117
- Apply middleware to individual routes:
118
-
119
- ```javascript
120
- import { authMiddleware } from './middleware/auth.js';
121
-
122
- target.register('/public', (ammo) => {
123
- ammo.fire({ public: true });
124
- });
125
-
126
- // Auth middleware only for this route
127
- target.register('/private', authMiddleware, (ammo) => {
128
- ammo.fire({ private: true, user: ammo.user });
129
- });
130
-
131
- // Multiple middleware
132
- target.register('/admin', authMiddleware, adminMiddleware, (ammo) => {
133
- ammo.fire({ admin: true });
134
- });
135
- ```
136
-
137
- ## File Organization
138
-
139
- ### Recommended Structure
140
-
141
- ```
142
- targets/
143
- ├── index.target.js # Root routes (/)
144
- ├── user.target.js # User routes (/user)
145
- ├── auth.target.js # Auth routes (/auth)
146
- └── api/
147
- ├── v1.target.js # API v1 routes (/api/v1)
148
- └── v2.target.js # API v2 routes (/api/v2)
149
- ```
150
-
151
- ### Example: user.target.js
152
-
153
- ```javascript
154
- import { Target } from 'te.js';
155
- import { authMiddleware } from '../middleware/auth.js';
156
-
157
- const users = new Target('/users');
158
-
159
- // Public route
160
- users.register('/register', (ammo) => {
161
- if (!ammo.POST) return ammo.notAllowed();
162
-
163
- const { email, password, name } = ammo.payload;
164
- // ... create user
165
- ammo.fire(201, { message: 'User created' });
166
- });
167
-
168
- // Protected routes
169
- users.midair(authMiddleware);
170
-
171
- users.register('/profile', (ammo) => {
172
- if (ammo.GET) {
173
- ammo.fire({ user: ammo.user });
174
- } else if (ammo.PUT) {
175
- // ... update profile
176
- ammo.fire({ message: 'Profile updated' });
177
- } else {
178
- ammo.notAllowed();
179
- }
180
- });
181
-
182
- users.register('/:id', (ammo) => {
183
- if (!ammo.GET) return ammo.notAllowed();
184
-
185
- const { id } = ammo.payload;
186
- // ... fetch user by id
187
- ammo.fire({ id, name: 'John Doe' });
188
- });
189
- ```
190
-
191
- ## Endpoint Metadata
192
-
193
- You can optionally pass a metadata object as the second argument to `register()`. This metadata is used by the [auto-documentation](./auto-docs.md) system to generate richer OpenAPI specs:
194
-
195
- ```javascript
196
- target.register('/users', {
197
- summary: 'User operations',
198
- description: 'Create and list users',
199
- methods: ['GET', 'POST'],
200
- request: {
201
- name: { type: 'string', required: true },
202
- email: { type: 'string', required: true }
203
- },
204
- response: {
205
- 200: { description: 'User list' },
206
- 201: { description: 'User created' }
207
- }
208
- }, (ammo) => {
209
- if (ammo.GET) return ammo.fire(getUsers());
210
- if (ammo.POST) return ammo.fire(201, createUser(ammo.payload));
211
- ammo.notAllowed();
212
- });
213
- ```
214
-
215
- When metadata is omitted, the auto-docs LLM infers everything from the handler source code.
216
-
217
- ## Method-Agnostic Handlers
218
-
219
- If a handler does not check any method flags (`ammo.GET`, `ammo.POST`, etc.), it is treated as accepting **all HTTP methods**. This is useful for simple endpoints:
220
-
221
- ```javascript
222
- target.register('/health', (ammo) => {
223
- ammo.fire({ status: 'ok' });
224
- });
225
- ```
226
-
227
- ## Listing All Routes
228
-
229
- Get all registered endpoints programmatically:
230
-
231
- ```javascript
232
- import { listAllEndpoints } from 'te.js';
233
-
234
- // Get flat list of paths
235
- const routes = listAllEndpoints();
236
- // ['/api/users', '/api/posts', '/auth/login', ...]
237
-
238
- // Get grouped by first path segment
239
- const grouped = listAllEndpoints(true);
240
- // {
241
- // api: ['/api/users', '/api/posts'],
242
- // auth: ['/auth/login', '/auth/register']
243
- // }
244
- ```
245
-
246
- ## Complete Example
247
-
248
- ```javascript
249
- // targets/products.target.js
250
- import { Target, TejError } from 'te.js';
251
- import { authMiddleware, adminMiddleware } from '../middleware/index.js';
252
-
253
- const products = new Target('/products');
254
-
255
- // Public: List all products
256
- products.register('/', (ammo) => {
257
- if (!ammo.GET) return ammo.notAllowed();
258
-
259
- const { category, page = 1, limit = 10 } = ammo.payload;
260
- // ... fetch products
261
- ammo.fire({ products: [], page, limit });
262
- });
263
-
264
- // Public: Get single product
265
- products.register('/:id', (ammo) => {
266
- if (!ammo.GET) return ammo.notAllowed();
267
-
268
- const { id } = ammo.payload;
269
- const product = findProduct(id);
270
-
271
- if (!product) {
272
- throw new TejError(404, 'Product not found');
273
- }
274
-
275
- ammo.fire(product);
276
- });
277
-
278
- // Protected: Create product (admin only)
279
- products.register('/create', authMiddleware, adminMiddleware, (ammo) => {
280
- if (!ammo.POST) return ammo.notAllowed();
281
-
282
- const { name, price, description } = ammo.payload;
283
- // ... create product
284
- ammo.fire(201, { id: 'new-id', name, price });
285
- });
286
-
287
- // Protected: Update product (admin only)
288
- products.register('/:id/update', authMiddleware, adminMiddleware, (ammo) => {
289
- if (!ammo.PUT) return ammo.notAllowed();
290
-
291
- const { id, ...updates } = ammo.payload;
292
- // ... update product
293
- ammo.fire({ message: 'Product updated' });
294
- });
295
- ```
296
-
297
- ## Next Steps
298
-
299
- - [Ammo](./ammo.md) — Handle requests and send responses
300
- - [Middleware](./middleware.md) — Global, target, and route-level middleware
301
- - [Auto-Documentation](./auto-docs.md) — Endpoint metadata for OpenAPI generation
302
-
1
+ # Routing with Targets
2
+
3
+ Tejas uses a **Target-based** routing system. A Target is similar to an Express Router—it groups related endpoints under a common base path.
4
+
5
+ ## Creating a Target
6
+
7
+ ```javascript
8
+ import { Target } from 'te.js';
9
+
10
+ const target = new Target('/api');
11
+ ```
12
+
13
+ ## Registering Endpoints
14
+
15
+ Use `register()` to add endpoints to a target:
16
+
17
+ ```javascript
18
+ target.register('/users', (ammo) => {
19
+ ammo.fire([{ id: 1, name: 'John' }]);
20
+ });
21
+ ```
22
+
23
+ This creates a route at `GET /api/users`.
24
+
25
+ ## Method Handling
26
+
27
+ Tejas routes are **method-agnostic** by default. Use the method flags on `ammo` to handle different HTTP methods:
28
+
29
+ ```javascript
30
+ target.register('/users', (ammo) => {
31
+ if (ammo.GET) {
32
+ // Handle GET /api/users
33
+ ammo.fire([{ id: 1, name: 'John' }]);
34
+ } else if (ammo.POST) {
35
+ // Handle POST /api/users
36
+ const { name, email } = ammo.payload;
37
+ ammo.fire(201, { id: 2, name, email });
38
+ } else {
39
+ ammo.notAllowed();
40
+ }
41
+ });
42
+ ```
43
+
44
+ ### Available Method Flags
45
+
46
+ - `ammo.GET`
47
+ - `ammo.POST`
48
+ - `ammo.PUT`
49
+ - `ammo.DELETE`
50
+ - `ammo.PATCH`
51
+ - `ammo.HEAD`
52
+ - `ammo.OPTIONS`
53
+
54
+ ## Parameterized Routes
55
+
56
+ Use `:param` syntax for dynamic route segments:
57
+
58
+ ```javascript
59
+ target.register('/users/:id', (ammo) => {
60
+ const { id } = ammo.payload;
61
+ ammo.fire({ userId: id });
62
+ });
63
+
64
+ target.register('/users/:userId/posts/:postId', (ammo) => {
65
+ const { userId, postId } = ammo.payload;
66
+ ammo.fire({ userId, postId });
67
+ });
68
+ ```
69
+
70
+ Route parameters are automatically extracted and added to `ammo.payload`.
71
+
72
+ ## Query Parameters
73
+
74
+ Query parameters are also available in `ammo.payload`:
75
+
76
+ ```javascript
77
+ // Request: GET /api/users?page=2&limit=10
78
+
79
+ target.register('/users', (ammo) => {
80
+ const { page, limit } = ammo.payload;
81
+ ammo.fire({ page, limit }); // { page: "2", limit: "10" }
82
+ });
83
+ ```
84
+
85
+ ## Route Priority
86
+
87
+ Routes are matched in the following order:
88
+
89
+ 1. **Exact matches** (most specific)
90
+ 2. **Parameterized routes** (in registration order)
91
+
92
+ ```javascript
93
+ // These don't conflict:
94
+ target.register('/users/me', handler); // Exact match for /users/me
95
+ target.register('/users/:id', handler); // Matches /users/123, /users/john
96
+ ```
97
+
98
+ ## Target-Level Middleware
99
+
100
+ Apply middleware to all routes in a target:
101
+
102
+ ```javascript
103
+ const api = new Target('/api');
104
+
105
+ // This middleware runs for ALL /api/* routes
106
+ api.midair((ammo, next) => {
107
+ console.log('API request:', ammo.path);
108
+ next();
109
+ });
110
+
111
+ api.register('/users', handler);
112
+ api.register('/posts', handler);
113
+ ```
114
+
115
+ ## Route-Specific Middleware
116
+
117
+ Apply middleware to individual routes:
118
+
119
+ ```javascript
120
+ import { authMiddleware } from './middleware/auth.js';
121
+
122
+ target.register('/public', (ammo) => {
123
+ ammo.fire({ public: true });
124
+ });
125
+
126
+ // Auth middleware only for this route
127
+ target.register('/private', authMiddleware, (ammo) => {
128
+ ammo.fire({ private: true, user: ammo.user });
129
+ });
130
+
131
+ // Multiple middleware
132
+ target.register('/admin', authMiddleware, adminMiddleware, (ammo) => {
133
+ ammo.fire({ admin: true });
134
+ });
135
+ ```
136
+
137
+ ## File Organization
138
+
139
+ ### Recommended Structure
140
+
141
+ ```
142
+ targets/
143
+ ├── index.target.js # Root routes (/)
144
+ ├── user.target.js # User routes (/user)
145
+ ├── auth.target.js # Auth routes (/auth)
146
+ └── api/
147
+ ├── v1.target.js # API v1 routes (/api/v1)
148
+ └── v2.target.js # API v2 routes (/api/v2)
149
+ ```
150
+
151
+ ### Example: user.target.js
152
+
153
+ ```javascript
154
+ import { Target } from 'te.js';
155
+ import { authMiddleware } from '../middleware/auth.js';
156
+
157
+ const users = new Target('/users');
158
+
159
+ // Public route
160
+ users.register('/register', (ammo) => {
161
+ if (!ammo.POST) return ammo.notAllowed();
162
+
163
+ const { email, password, name } = ammo.payload;
164
+ // ... create user
165
+ ammo.fire(201, { message: 'User created' });
166
+ });
167
+
168
+ // Protected routes
169
+ users.midair(authMiddleware);
170
+
171
+ users.register('/profile', (ammo) => {
172
+ if (ammo.GET) {
173
+ ammo.fire({ user: ammo.user });
174
+ } else if (ammo.PUT) {
175
+ // ... update profile
176
+ ammo.fire({ message: 'Profile updated' });
177
+ } else {
178
+ ammo.notAllowed();
179
+ }
180
+ });
181
+
182
+ users.register('/:id', (ammo) => {
183
+ if (!ammo.GET) return ammo.notAllowed();
184
+
185
+ const { id } = ammo.payload;
186
+ // ... fetch user by id
187
+ ammo.fire({ id, name: 'John Doe' });
188
+ });
189
+ ```
190
+
191
+ ## Endpoint Metadata
192
+
193
+ You can optionally pass a metadata object as the second argument to `register()`. This metadata is used by the [auto-documentation](./auto-docs.md) system to generate richer OpenAPI specs:
194
+
195
+ ```javascript
196
+ target.register('/users', {
197
+ summary: 'User operations',
198
+ description: 'Create and list users',
199
+ methods: ['GET', 'POST'],
200
+ request: {
201
+ name: { type: 'string', required: true },
202
+ email: { type: 'string', required: true }
203
+ },
204
+ response: {
205
+ 200: { description: 'User list' },
206
+ 201: { description: 'User created' }
207
+ }
208
+ }, (ammo) => {
209
+ if (ammo.GET) return ammo.fire(getUsers());
210
+ if (ammo.POST) return ammo.fire(201, createUser(ammo.payload));
211
+ ammo.notAllowed();
212
+ });
213
+ ```
214
+
215
+ When metadata is omitted, the auto-docs LLM infers everything from the handler source code.
216
+
217
+ ## Method-Agnostic Handlers
218
+
219
+ If a handler does not check any method flags (`ammo.GET`, `ammo.POST`, etc.), it is treated as accepting **all HTTP methods**. This is useful for simple endpoints:
220
+
221
+ ```javascript
222
+ target.register('/health', (ammo) => {
223
+ ammo.fire({ status: 'ok' });
224
+ });
225
+ ```
226
+
227
+ ## Listing All Routes
228
+
229
+ Get all registered endpoints programmatically:
230
+
231
+ ```javascript
232
+ import { listAllEndpoints } from 'te.js';
233
+
234
+ // Get flat list of paths
235
+ const routes = listAllEndpoints();
236
+ // ['/api/users', '/api/posts', '/auth/login', ...]
237
+
238
+ // Get grouped by first path segment
239
+ const grouped = listAllEndpoints(true);
240
+ // {
241
+ // api: ['/api/users', '/api/posts'],
242
+ // auth: ['/auth/login', '/auth/register']
243
+ // }
244
+ ```
245
+
246
+ ## Complete Example
247
+
248
+ ```javascript
249
+ // targets/products.target.js
250
+ import { Target, TejError } from 'te.js';
251
+ import { authMiddleware, adminMiddleware } from '../middleware/index.js';
252
+
253
+ const products = new Target('/products');
254
+
255
+ // Public: List all products
256
+ products.register('/', (ammo) => {
257
+ if (!ammo.GET) return ammo.notAllowed();
258
+
259
+ const { category, page = 1, limit = 10 } = ammo.payload;
260
+ // ... fetch products
261
+ ammo.fire({ products: [], page, limit });
262
+ });
263
+
264
+ // Public: Get single product
265
+ products.register('/:id', (ammo) => {
266
+ if (!ammo.GET) return ammo.notAllowed();
267
+
268
+ const { id } = ammo.payload;
269
+ const product = findProduct(id);
270
+
271
+ if (!product) {
272
+ throw new TejError(404, 'Product not found');
273
+ }
274
+
275
+ ammo.fire(product);
276
+ });
277
+
278
+ // Protected: Create product (admin only)
279
+ products.register('/create', authMiddleware, adminMiddleware, (ammo) => {
280
+ if (!ammo.POST) return ammo.notAllowed();
281
+
282
+ const { name, price, description } = ammo.payload;
283
+ // ... create product
284
+ ammo.fire(201, { id: 'new-id', name, price });
285
+ });
286
+
287
+ // Protected: Update product (admin only)
288
+ products.register('/:id/update', authMiddleware, adminMiddleware, (ammo) => {
289
+ if (!ammo.PUT) return ammo.notAllowed();
290
+
291
+ const { id, ...updates } = ammo.payload;
292
+ // ... update product
293
+ ammo.fire({ message: 'Product updated' });
294
+ });
295
+ ```
296
+
297
+ ## Next Steps
298
+
299
+ - [Ammo](./ammo.md) — Handle requests and send responses
300
+ - [Middleware](./middleware.md) — Global, target, and route-level middleware
301
+ - [Auto-Documentation](./auto-docs.md) — Endpoint metadata for OpenAPI generation
302
+