te.js 2.0.0 → 2.0.3

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/example/README.md DELETED
@@ -1,155 +0,0 @@
1
- # te.js Example
2
-
3
- A comprehensive example demonstrating te.js framework features: routing, middleware, rate limiting, file uploads, services, and optional Redis caching.
4
-
5
- ## Quick Start
6
-
7
- ```bash
8
- npm install
9
- npm start
10
- ```
11
-
12
- Server runs at `http://localhost:1403`
13
-
14
- ## Project Structure
15
-
16
- ```
17
- example/
18
- ├── index.js # App setup, global middleware, rate limit
19
- ├── targets/ # Routes + handlers
20
- │ ├── index.target.js # /, /health, /routes
21
- │ ├── users.target.js # CRUD + file uploads (/users, /users/:id, …)
22
- │ └── cache.target.js # Redis key-value (optional)
23
- └── services/ # Business logic
24
- ├── user.service.js # In-memory user CRUD
25
- └── cache.service.js # Redis wrapper
26
- ```
27
-
28
- ## Endpoints
29
-
30
- ### Index
31
-
32
- | Method | Path | Description |
33
- | ------ | --------- | ------------------------------------ |
34
- | GET | `/` | Default HTML entry |
35
- | GET | `/health` | Health check |
36
- | GET | `/routes` | List all registered routes (grouped) |
37
-
38
- ### Users
39
-
40
- | Method | Path | Description |
41
- | ------ | ------------------------------- | --------------------------------- |
42
- | GET | `/users` | List all users |
43
- | POST | `/users` | Create user (JSON body) |
44
- | GET | `/users/:id` | Get user by id |
45
- | PUT | `/users/:id` | Update user |
46
- | DELETE | `/users/:id` | Delete user |
47
- | POST | `/users/:id/updateProfileImage` | Single file (field: image) |
48
- | POST | `/users/:id/uploadDocuments` | Multiple files (field: documents) |
49
-
50
- ### Cache (requires Redis)
51
-
52
- | Method | Path | Description |
53
- | ------ | ------------- | ---------------------------------- |
54
- | GET | `/cache/:key` | Get value |
55
- | POST | `/cache` | Set value (body: key, value, ttl?) |
56
-
57
- ## curl Examples
58
-
59
- ```bash
60
- # Health check
61
- curl http://localhost:1403/health
62
-
63
- # List routes
64
- curl http://localhost:1403/routes
65
-
66
- # Users CRUD
67
- curl -X POST http://localhost:1403/users -H "Content-Type: application/json" -d '{"name":"John","email":"john@example.com"}'
68
- curl http://localhost:1403/users
69
- curl http://localhost:1403/users/1
70
- curl -X PUT http://localhost:1403/users/1 -H "Content-Type: application/json" -d '{"name":"Jane"}'
71
- curl -X DELETE http://localhost:1403/users/1
72
-
73
- # File upload (single)
74
- curl -X POST http://localhost:1403/users/1/updateProfileImage -F "image=@./photo.jpg"
75
-
76
- # File upload (multiple)
77
- curl -X POST http://localhost:1403/users/1/uploadDocuments -F "documents=@./doc1.pdf" -F "documents=@./doc2.pdf"
78
-
79
- # Cache (requires REDIS_URL)
80
- REDIS_URL=redis://localhost:6379 npm start
81
- curl -X POST http://localhost:1403/cache -H "Content-Type: application/json" -d '{"key":"foo","value":"bar","ttl":60}'
82
- curl http://localhost:1403/cache/foo
83
- ```
84
-
85
- ## Optional: Redis
86
-
87
- To enable cache endpoints:
88
-
89
- ```bash
90
- npm run start:redis
91
- ```
92
-
93
- Or set `REDIS_URL` before starting:
94
-
95
- ```bash
96
- # Linux/macOS
97
- REDIS_URL=redis://localhost:6379 npm start
98
-
99
- # Windows (PowerShell)
100
- $env:REDIS_URL="redis://localhost:6379"; npm start
101
- ```
102
-
103
- ## Features Demonstrated
104
-
105
- - **Routing** — Flat targets, parameterized paths (`:id`)
106
- - **HTTP methods** — `ammo.GET`, `ammo.POST`, `ammo.notAllowed()`
107
- - **Body parsing** — JSON, multipart/form-data
108
- - **Error handling** — `TejError`, `ammo.notFound()`, `ammo.throw()`
109
- - **File uploads** — `TejFileUploader.file()`, `TejFileUploader.files()`
110
- - **Middleware** — Global (`app.midair`), target-level (`target.midair`)
111
- - **Rate limiting** — Memory store (60 req/min)
112
- - **Services** — Business logic in `services/`
113
- - **listAllEndpoints** — Route discovery at `/routes`
114
-
115
- ## Documentation generation
116
-
117
- Generate OpenAPI docs and serve them at `/docs`:
118
-
119
- ```bash
120
- npx tejas generate:docs
121
- ```
122
-
123
- Then use `app.serveDocs({ specPath: './openapi.json' })` in `index.js` (already configured in this example).
124
-
125
- ### Generate docs on push to production (inbuilt)
126
-
127
- To regenerate docs automatically when pushing to your production branch:
128
-
129
- 1. **Configure** the production branch and (optionally) doc options in `tejas.config.json`:
130
-
131
- ```json
132
- "docs": {
133
- "dirTargets": "targets",
134
- "output": "./openapi.json",
135
- "productionBranch": "main"
136
- }
137
- ```
138
-
139
- Set `LLM_API_KEY` (or `OPENAI_API_KEY`) in the environment for non-interactive generation.
140
-
141
- 2. **Add a pre-push hook** (e.g. with Husky):
142
-
143
- ```bash
144
- npx husky add .husky/pre-push "npx tejas docs:on-push"
145
- ```
146
-
147
- When you push to `main` (or your configured branch), the framework will run `tejas generate:docs --ci` before the push completes, so `openapi.json` (and optionally `API_OVERVIEW.md`) stay in sync.
148
-
149
- For CI pipelines, run:
150
-
151
- ```bash
152
- npx tejas generate:docs --ci
153
- ```
154
-
155
- See [te.js documentation](https://tejas-documentation.vercel.app) for more.
package/example/index.js DELETED
@@ -1,29 +0,0 @@
1
- import Tejas from 'te.js';
2
-
3
- const app = new Tejas();
4
-
5
- // Global middleware: request logging
6
- app.midair((ammo, next) => {
7
- console.log(`[${new Date().toISOString()}] ${ammo.method} ${ammo.path}`);
8
- next();
9
- });
10
-
11
- // Rate limiting (memory store - no Redis required)
12
- app.withRateLimit({
13
- maxRequests: 60,
14
- timeWindowSeconds: 60,
15
- });
16
-
17
- // Serve API docs at /docs (requires openapi.json from `tejas generate:docs`)
18
- app.serveDocs({ specPath: './openapi.json' });
19
-
20
- // Optional: Redis for /cache endpoints. Set REDIS_URL to enable.
21
- const redisUrl = process.env.REDIS_URL;
22
-
23
- app.takeoff(
24
- redisUrl
25
- ? {
26
- withRedis: { url: redisUrl },
27
- }
28
- : {},
29
- );
@@ -1,9 +0,0 @@
1
- const auth = (ammo, next) => {
2
- if (ammo.headers.authorization === "Bearer 123") {
3
- next();
4
- } else {
5
- return ammo.unauthorized();
6
- }
7
- };
8
-
9
- export default auth;
@@ -1,6 +0,0 @@
1
- const globalMidair = async (ammo, next) => {
2
- console.log('Global middleware');
3
- await next();
4
- };
5
-
6
- export { globalMidair };
@@ -1,390 +0,0 @@
1
- {
2
- "openapi": "3.0.3",
3
- "info": {
4
- "title": "API",
5
- "version": "1.0.0",
6
- "description": "# API Documentation\n\n**Version:** 1.0.0\n\n## Project Summary\n\nThis API provides a lightweight service combining user account management, a Redis-backed caching layer, and system introspection utilities. It supports full CRUD operations on user resources—including file uploads for profile images and bulk documents—offers key-value caching with optional TTL, and exposes health-check and route discovery endpoints for operational monitoring and API introspection. User data is maintained in-memory for demonstration purposes, and uploaded files are stored on disk with configurable size limits.\n\n---\n\n## APIs Available\n\n### Users\nManages user accounts with full CRUD operations: create, retrieve, update, and delete users. Additionally supports profile image uploads and bulk document uploads, with files stored on disk and configurable size limits.\n\n### Cache\nProvides a key-value caching layer backed by Redis. Store arbitrary values with an optional time-to-live (TTL) and retrieve them by key. A middleware guard ensures the Redis service is available before processing any cache request.\n\n### System & Discovery\nCore application utilities including a default landing endpoint, a health-check endpoint reporting server status with a current timestamp, and a route discovery endpoint that lists all registered endpoints grouped by source for API introspection.\n\n---\n\n## Key Endpoints\n\n### Getting Started\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `GET` | `/` | Default landing entry point for the API. |\n| `GET` | `/health` | Health check — returns server status and current timestamp. |\n| `GET` | `/routes` | Route discovery — lists all registered endpoints grouped by source. |\n\n### User Management\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `GET` | `/users` | Retrieve a list of all users. |\n| `POST` | `/users` | Create a new user. |\n| `GET` | `/users/{id}` | Retrieve a specific user by ID. |\n| `PUT` | `/users/{id}` | Update an existing user by ID. |\n| `DELETE` | `/users/{id}` | Delete a user by ID. |\n| `GET` | `/users/{id}/updateProfileImage` | Upload or update a user's profile image. |\n| `GET` | `/users/{id}/uploadDocuments` | Bulk upload documents for a user. |\n\n### Cache Operations\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/cache` | Store a value in the cache with an optional TTL. |\n| `GET` | `/cache/{key}` | Retrieve a cached value by its key. |\n\n---\n\n## Additional Notes\n\n### Data Storage\n- **User data** is maintained in-memory and is not persisted across server restarts (demonstration mode).\n- **Uploaded files** (profile images, documents) are stored on disk with configurable size limits.\n\n### Cache Availability\nAll cache endpoints are protected by a middleware guard that verifies the Redis service is reachable before processing requests. If Redis is unavailable, cache requests will be rejected before reaching the handler.\n\n### File Uploads\n- **Profile images**: Single-file upload tied to a specific user via `/users/{id}/updateProfileImage`.\n- **Bulk documents**: Multi-file upload supported via `/users/{id}/uploadDocuments`.\n\nFile size limits are configurable at the application level.\n\n---\n\n## Quick Start\n\n1. **Verify the API is running** — call `GET /health` and confirm a successful status response with a timestamp.\n2. **Explore available routes** — call `GET /routes` to discover all registered endpoints.\n3. **Create a user** — send a `POST` request to `/users` with the required user payload.\n4. **Store and retrieve cache entries** — use `POST /cache` to set a key-value pair, then `GET /cache/{key}` to retrieve it."
7
- },
8
- "tags": [
9
- {
10
- "name": "Users",
11
- "description": "Manages user accounts with full CRUD operations including creation, retrieval, updating, and deletion. Also supports profile image uploads and bulk document uploads, storing files on disk with configurable size limits. User data is maintained in-memory for demonstration purposes."
12
- },
13
- {
14
- "name": "Cache",
15
- "description": "Provides a key-value caching layer backed by Redis. Consumers can store arbitrary values with an optional time-to-live and retrieve them by key. A middleware guard ensures the Redis-backed cache service is available before processing any request."
16
- },
17
- {
18
- "name": "System & Discovery",
19
- "description": "Provides core application utilities: a default landing entry point, a health-check endpoint that reports server status with a current timestamp, and a route discovery endpoint that lists all registered endpoints grouped by their source, enabling API introspection."
20
- }
21
- ],
22
- "paths": {
23
- "/cache/{key}": {
24
- "get": {
25
- "summary": "Get cached value by key",
26
- "description": "Retrieves a cached value from Redis by its key. Requires the cache service (Redis) to be available.",
27
- "parameters": [
28
- {
29
- "name": "key",
30
- "in": "path",
31
- "required": true,
32
- "description": "Path parameter: key",
33
- "schema": {
34
- "type": "string"
35
- }
36
- }
37
- ],
38
- "responses": {
39
- "200": {
40
- "description": "Cached value found and returned successfully"
41
- },
42
- "404": {
43
- "description": "No cached value found for the given key"
44
- },
45
- "405": {
46
- "description": "Method not allowed (non-GET request made to this endpoint)"
47
- },
48
- "503": {
49
- "description": "Cache service unavailable. Redis is not configured or reachable."
50
- }
51
- },
52
- "tags": [
53
- "Cache"
54
- ]
55
- }
56
- },
57
- "/cache": {
58
- "post": {
59
- "summary": "Store a value in the cache",
60
- "description": "Sets a key-value pair in the Redis cache with an optional TTL (time-to-live) in seconds. Requires the cache service (Redis) to be available.",
61
- "requestBody": {
62
- "required": true,
63
- "content": {
64
- "application/json": {
65
- "schema": {
66
- "type": "object",
67
- "properties": {
68
- "key": {
69
- "type": "string",
70
- "description": "The cache key under which to store the value"
71
- },
72
- "value": {
73
- "type": "any",
74
- "description": "The value to cache; can be any type but must not be undefined"
75
- },
76
- "ttl": {
77
- "type": "integer",
78
- "description": "Time-to-live in seconds for the cached entry; if omitted, the entry does not expire automatically"
79
- }
80
- },
81
- "required": [
82
- "key",
83
- "value"
84
- ]
85
- }
86
- }
87
- }
88
- },
89
- "responses": {
90
- "201": {
91
- "description": "Value cached successfully. Returns an object with a confirmation message and the cache key."
92
- },
93
- "400": {
94
- "description": "Validation error: 'key' and 'value' are required fields"
95
- },
96
- "405": {
97
- "description": "Method not allowed. Only POST is accepted on this endpoint."
98
- },
99
- "503": {
100
- "description": "Cache service unavailable. Redis is not configured or not reachable (REDIS_URL not set)."
101
- }
102
- },
103
- "tags": [
104
- "Cache"
105
- ]
106
- }
107
- },
108
- "/": {
109
- "get": {
110
- "summary": "Submit data to the default entry endpoint",
111
- "description": "Handles POST requests to the root endpoint by returning the default entry response. No specific body processing is performed.\n\nAccepts any HTTP method: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS.",
112
- "responses": {
113
- "200": {
114
- "description": "Default entry content returned successfully"
115
- }
116
- },
117
- "tags": [
118
- "System & Discovery"
119
- ]
120
- }
121
- },
122
- "/health": {
123
- "get": {
124
- "summary": "Post health check request",
125
- "description": "Accepts a POST request and returns the current health status and timestamp. No request body is required; any provided body is ignored.\n\nAccepts any HTTP method: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS.",
126
- "responses": {
127
- "200": {
128
- "description": "Service is healthy. Returns an object with `status` ('ok') and `timestamp` (ISO 8601 string)."
129
- }
130
- },
131
- "tags": [
132
- "System & Discovery"
133
- ]
134
- }
135
- },
136
- "/routes": {
137
- "get": {
138
- "summary": "Create or trigger route listing via POST",
139
- "description": "Returns the same grouped listing of all registered endpoints. The handler does not differentiate by HTTP method, so POST behaves identically to GET.\n\nAccepts any HTTP method: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS.",
140
- "responses": {
141
- "200": {
142
- "description": "A grouped object of all registered endpoints and their supported methods"
143
- }
144
- },
145
- "tags": [
146
- "System & Discovery"
147
- ]
148
- }
149
- },
150
- "/users": {
151
- "get": {
152
- "summary": "List all users",
153
- "description": "Returns an array of all users currently stored in the system.",
154
- "responses": {
155
- "200": {
156
- "description": "An array of user objects. Returns an empty array if no users exist."
157
- }
158
- },
159
- "tags": [
160
- "Users"
161
- ]
162
- },
163
- "post": {
164
- "summary": "Create a new user",
165
- "description": "Creates a new user with the provided name and email. Returns the newly created user object with a generated id and createdAt timestamp.",
166
- "requestBody": {
167
- "required": true,
168
- "content": {
169
- "application/json": {
170
- "schema": {
171
- "type": "object",
172
- "properties": {
173
- "name": {
174
- "type": "string"
175
- },
176
- "email": {
177
- "type": "string",
178
- "format": "email"
179
- }
180
- },
181
- "required": [
182
- "name",
183
- "email"
184
- ]
185
- }
186
- }
187
- }
188
- },
189
- "responses": {
190
- "201": {
191
- "description": "User created successfully. Returns the new user object including id, name, email, and createdAt fields."
192
- },
193
- "400": {
194
- "description": "Validation error. Both name and email are required."
195
- }
196
- },
197
- "tags": [
198
- "Users"
199
- ]
200
- }
201
- },
202
- "/users/{id}": {
203
- "get": {
204
- "summary": "Get user by id",
205
- "description": "Retrieves a single user by their unique identifier.",
206
- "parameters": [
207
- {
208
- "name": "id",
209
- "in": "path",
210
- "required": true,
211
- "description": "Path parameter: id",
212
- "schema": {
213
- "type": "string"
214
- }
215
- }
216
- ],
217
- "responses": {
218
- "200": {
219
- "description": "User object returned successfully"
220
- },
221
- "404": {
222
- "description": "User not found"
223
- }
224
- },
225
- "tags": [
226
- "Users"
227
- ]
228
- },
229
- "put": {
230
- "summary": "Update user",
231
- "description": "Updates an existing user's name and/or email by their unique identifier.",
232
- "parameters": [
233
- {
234
- "name": "id",
235
- "in": "path",
236
- "required": true,
237
- "description": "Path parameter: id",
238
- "schema": {
239
- "type": "string"
240
- }
241
- }
242
- ],
243
- "requestBody": {
244
- "required": true,
245
- "content": {
246
- "application/json": {
247
- "schema": {
248
- "type": "object",
249
- "properties": {
250
- "name": {
251
- "type": "string"
252
- },
253
- "email": {
254
- "type": "string",
255
- "format": "email"
256
- }
257
- }
258
- }
259
- }
260
- }
261
- },
262
- "responses": {
263
- "200": {
264
- "description": "User updated successfully"
265
- },
266
- "404": {
267
- "description": "User not found"
268
- }
269
- },
270
- "tags": [
271
- "Users"
272
- ]
273
- },
274
- "delete": {
275
- "summary": "Delete user",
276
- "description": "Deletes a user by their unique identifier.",
277
- "parameters": [
278
- {
279
- "name": "id",
280
- "in": "path",
281
- "required": true,
282
- "description": "Path parameter: id",
283
- "schema": {
284
- "type": "string"
285
- }
286
- }
287
- ],
288
- "responses": {
289
- "204": {
290
- "description": "User deleted successfully"
291
- },
292
- "404": {
293
- "description": "User not found"
294
- }
295
- },
296
- "tags": [
297
- "Users"
298
- ]
299
- }
300
- },
301
- "/users/{id}/updateProfileImage": {
302
- "get": {
303
- "summary": "Upload a profile image for a user",
304
- "description": "Uploads a single profile image file for the specified user. Uses multipart/form-data with a file field named 'image'. Maximum file size is 5MB. Files are stored in 'public/uploads'.\n\nAccepts any HTTP method: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS.",
305
- "parameters": [
306
- {
307
- "name": "id",
308
- "in": "path",
309
- "required": true,
310
- "description": "Path parameter: id",
311
- "schema": {
312
- "type": "string"
313
- }
314
- }
315
- ],
316
- "requestBody": {
317
- "required": true,
318
- "content": {
319
- "application/json": {
320
- "schema": {
321
- "type": "object",
322
- "properties": {
323
- "image": {
324
- "type": "file",
325
- "description": "The profile image file to upload (max 5MB)"
326
- }
327
- },
328
- "required": [
329
- "image"
330
- ]
331
- }
332
- }
333
- }
334
- },
335
- "responses": {
336
- "200": {
337
- "description": "Profile image uploaded successfully. Returns a message and the uploaded file metadata."
338
- }
339
- },
340
- "tags": [
341
- "Users"
342
- ]
343
- }
344
- },
345
- "/users/{id}/uploadDocuments": {
346
- "get": {
347
- "summary": "Upload documents for a user",
348
- "description": "Uploads multiple document files for the user identified by :id. Files are processed by the TejFileUploader middleware with a max file size of 5MB each and stored in 'public/uploads'.\n\nAccepts any HTTP method: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS.",
349
- "parameters": [
350
- {
351
- "name": "id",
352
- "in": "path",
353
- "required": true,
354
- "description": "Path parameter: id",
355
- "schema": {
356
- "type": "string"
357
- }
358
- }
359
- ],
360
- "requestBody": {
361
- "required": true,
362
- "content": {
363
- "application/json": {
364
- "schema": {
365
- "type": "object",
366
- "properties": {
367
- "documents": {
368
- "type": "array",
369
- "description": "Array of document files to upload. Field name must be 'documents'. Each file must not exceed 5MB."
370
- }
371
- },
372
- "required": [
373
- "documents"
374
- ]
375
- }
376
- }
377
- }
378
- },
379
- "responses": {
380
- "200": {
381
- "description": "Documents uploaded successfully. Returns a message indicating the number of documents uploaded and an array of file metadata."
382
- }
383
- },
384
- "tags": [
385
- "Users"
386
- ]
387
- }
388
- }
389
- }
390
- }
@@ -1,23 +0,0 @@
1
- {
2
- "name": "example",
3
- "version": "1.0.0",
4
- "description": "Comprehensive te.js example - routing, middleware, file uploads, services",
5
- "main": "index.js",
6
- "type": "module",
7
- "scripts": {
8
- "start": "node index.js",
9
- "start:redis": "node start-redis.js",
10
- "test": "echo \"Error: no test specified\" && exit 1",
11
- "prettify": "prettier --write --ignore-unknown"
12
- },
13
- "keywords": [],
14
- "author": "",
15
- "license": "ISC",
16
- "dependencies": {
17
- "cors": "^2.8.5",
18
- "mongoose": "^8.3.1",
19
- "redis": "^4.7.0",
20
- "te.js": "file:..",
21
- "tej-env": "^1.0.2"
22
- }
23
- }
@@ -1,25 +0,0 @@
1
- /**
2
- * Cache service - Redis wrapper for key-value storage.
3
- * Requires Redis connection via app.takeoff({ withRedis: { url } }).
4
- */
5
-
6
- import dbManager from 'te.js/database/index.js';
7
-
8
- export function isAvailable() {
9
- const { exists } = dbManager.hasConnection('redis', {});
10
- return exists;
11
- }
12
-
13
- export async function get(key) {
14
- const redis = dbManager.getConnection('redis');
15
- return redis.get(key);
16
- }
17
-
18
- export async function set(key, value, ttlSeconds) {
19
- const redis = dbManager.getConnection('redis');
20
- if (ttlSeconds) {
21
- await redis.setEx(key, ttlSeconds, String(value));
22
- } else {
23
- await redis.set(key, String(value));
24
- }
25
- }
@@ -1,42 +0,0 @@
1
- /**
2
- * User service - in-memory CRUD for demo purposes.
3
- * Demonstrates business logic extraction from route handlers.
4
- */
5
-
6
- const store = [];
7
- let nextId = 1;
8
-
9
- export default {
10
- list() {
11
- return [...store];
12
- },
13
-
14
- getById(id) {
15
- return store.find((u) => String(u.id) === String(id));
16
- },
17
-
18
- create({ name, email }) {
19
- if (!name || !email) {
20
- return null;
21
- }
22
- const user = { id: nextId++, name, email, createdAt: new Date().toISOString() };
23
- store.push(user);
24
- return user;
25
- },
26
-
27
- update(id, { name, email }) {
28
- const user = this.getById(id);
29
- if (!user) return null;
30
- if (name !== undefined) user.name = name;
31
- if (email !== undefined) user.email = email;
32
- user.updatedAt = new Date().toISOString();
33
- return user;
34
- },
35
-
36
- delete(id) {
37
- const index = store.findIndex((u) => String(u.id) === String(id));
38
- if (index === -1) return false;
39
- store.splice(index, 1);
40
- return true;
41
- },
42
- };