te.js 2.1.0 → 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 (66) hide show
  1. package/README.md +197 -196
  2. package/auto-docs/analysis/handler-analyzer.js +58 -58
  3. package/auto-docs/analysis/source-resolver.js +101 -101
  4. package/auto-docs/constants.js +37 -37
  5. package/auto-docs/docs-llm/index.js +7 -7
  6. package/auto-docs/docs-llm/prompts.js +222 -222
  7. package/auto-docs/docs-llm/provider.js +132 -132
  8. package/auto-docs/index.js +146 -146
  9. package/auto-docs/openapi/endpoint-processor.js +277 -277
  10. package/auto-docs/openapi/generator.js +107 -107
  11. package/auto-docs/openapi/level3.js +131 -131
  12. package/auto-docs/openapi/spec-builders.js +244 -244
  13. package/auto-docs/ui/docs-ui.js +186 -186
  14. package/auto-docs/utils/logger.js +17 -17
  15. package/auto-docs/utils/strip-usage.js +10 -10
  16. package/cli/docs-command.js +315 -315
  17. package/cli/fly-command.js +71 -71
  18. package/cli/index.js +56 -56
  19. package/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 -490
  25. package/docs/auto-docs.md +216 -216
  26. package/docs/cli.md +152 -152
  27. package/docs/configuration.md +275 -275
  28. package/docs/database.md +390 -390
  29. package/docs/error-handling.md +438 -438
  30. package/docs/file-uploads.md +333 -333
  31. package/docs/getting-started.md +214 -214
  32. package/docs/middleware.md +355 -355
  33. package/docs/rate-limiting.md +393 -393
  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 -415
  48. package/server/endpoint.js +97 -74
  49. package/server/error.js +9 -9
  50. package/server/errors/code-context.js +125 -125
  51. package/server/errors/llm-error-service.js +140 -140
  52. package/server/files/helper.js +33 -33
  53. package/server/files/uploader.js +143 -143
  54. package/server/handler.js +158 -119
  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 -402
  61. package/utils/auto-register.js +17 -17
  62. package/utils/configuration.js +64 -64
  63. package/utils/errors-llm-config.js +84 -84
  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
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
+