qhttpx 1.8.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 (197) hide show
  1. package/.eslintrc.json +22 -0
  2. package/.github/workflows/ci.yml +32 -0
  3. package/.github/workflows/npm-publish.yml +37 -0
  4. package/.github/workflows/release.yml +21 -0
  5. package/.prettierrc +7 -0
  6. package/CHANGELOG.md +145 -0
  7. package/LICENSE +21 -0
  8. package/README.md +343 -0
  9. package/dist/package.json +61 -0
  10. package/dist/src/benchmarks/compare-frameworks.js +119 -0
  11. package/dist/src/benchmarks/quantam-users.js +56 -0
  12. package/dist/src/benchmarks/simple-json.js +58 -0
  13. package/dist/src/benchmarks/ultra-mode.js +122 -0
  14. package/dist/src/cli/index.js +200 -0
  15. package/dist/src/client/index.js +72 -0
  16. package/dist/src/core/batch.js +97 -0
  17. package/dist/src/core/body-parser.js +121 -0
  18. package/dist/src/core/buffer-pool.js +70 -0
  19. package/dist/src/core/config.js +50 -0
  20. package/dist/src/core/fusion.js +183 -0
  21. package/dist/src/core/logger.js +49 -0
  22. package/dist/src/core/metrics.js +111 -0
  23. package/dist/src/core/resources.js +25 -0
  24. package/dist/src/core/scheduler.js +85 -0
  25. package/dist/src/core/scope.js +68 -0
  26. package/dist/src/core/serializer.js +44 -0
  27. package/dist/src/core/server.js +905 -0
  28. package/dist/src/core/stream.js +71 -0
  29. package/dist/src/core/tasks.js +87 -0
  30. package/dist/src/core/types.js +19 -0
  31. package/dist/src/core/websocket.js +86 -0
  32. package/dist/src/core/worker-queue.js +73 -0
  33. package/dist/src/database/adapters/memory.js +90 -0
  34. package/dist/src/database/adapters/mongo.js +141 -0
  35. package/dist/src/database/adapters/postgres.js +111 -0
  36. package/dist/src/database/adapters/sqlite.js +42 -0
  37. package/dist/src/database/coalescer.js +134 -0
  38. package/dist/src/database/manager.js +87 -0
  39. package/dist/src/database/types.js +2 -0
  40. package/dist/src/index.js +61 -0
  41. package/dist/src/middleware/compression.js +133 -0
  42. package/dist/src/middleware/cors.js +66 -0
  43. package/dist/src/middleware/presets.js +33 -0
  44. package/dist/src/middleware/rate-limit.js +77 -0
  45. package/dist/src/middleware/security.js +69 -0
  46. package/dist/src/middleware/static.js +191 -0
  47. package/dist/src/openapi/generator.js +149 -0
  48. package/dist/src/router/radix-router.js +89 -0
  49. package/dist/src/router/radix-tree.js +81 -0
  50. package/dist/src/router/router.js +146 -0
  51. package/dist/src/testing/index.js +84 -0
  52. package/dist/src/utils/cookies.js +59 -0
  53. package/dist/src/utils/logger.js +45 -0
  54. package/dist/src/utils/signals.js +31 -0
  55. package/dist/src/utils/sse.js +32 -0
  56. package/dist/src/validation/index.js +19 -0
  57. package/dist/src/validation/simple.js +102 -0
  58. package/dist/src/validation/types.js +12 -0
  59. package/dist/src/validation/zod.js +18 -0
  60. package/dist/src/views/index.js +17 -0
  61. package/dist/src/views/types.js +2 -0
  62. package/dist/tests/adapters.test.js +106 -0
  63. package/dist/tests/batch.test.js +117 -0
  64. package/dist/tests/body-parser.test.js +52 -0
  65. package/dist/tests/compression-sse.test.js +87 -0
  66. package/dist/tests/cookies.test.js +63 -0
  67. package/dist/tests/cors.test.js +55 -0
  68. package/dist/tests/database.test.js +80 -0
  69. package/dist/tests/dx.test.js +64 -0
  70. package/dist/tests/ecosystem.test.js +133 -0
  71. package/dist/tests/features.test.js +47 -0
  72. package/dist/tests/fusion.test.js +92 -0
  73. package/dist/tests/http-basic.test.js +124 -0
  74. package/dist/tests/logger.test.js +33 -0
  75. package/dist/tests/middleware.test.js +109 -0
  76. package/dist/tests/observability.test.js +59 -0
  77. package/dist/tests/openapi.test.js +64 -0
  78. package/dist/tests/plugin.test.js +65 -0
  79. package/dist/tests/plugins.test.js +71 -0
  80. package/dist/tests/rate-limit.test.js +77 -0
  81. package/dist/tests/resources.test.js +44 -0
  82. package/dist/tests/scheduler.test.js +46 -0
  83. package/dist/tests/schema-routes.test.js +77 -0
  84. package/dist/tests/security.test.js +83 -0
  85. package/dist/tests/server-db.test.js +72 -0
  86. package/dist/tests/smoke.test.js +10 -0
  87. package/dist/tests/sqlite-fusion.test.js +92 -0
  88. package/dist/tests/static.test.js +102 -0
  89. package/dist/tests/stream.test.js +44 -0
  90. package/dist/tests/task-metrics.test.js +53 -0
  91. package/dist/tests/tasks.test.js +62 -0
  92. package/dist/tests/testing.test.js +47 -0
  93. package/dist/tests/validation.test.js +107 -0
  94. package/dist/tests/websocket.test.js +146 -0
  95. package/dist/vitest.config.js +9 -0
  96. package/docs/AEGIS.md +76 -0
  97. package/docs/BENCHMARKS.md +36 -0
  98. package/docs/CAPABILITIES.md +70 -0
  99. package/docs/CLI.md +43 -0
  100. package/docs/DATABASE.md +142 -0
  101. package/docs/ECOSYSTEM.md +146 -0
  102. package/docs/NEXT_STEPS.md +99 -0
  103. package/docs/OPENAPI.md +99 -0
  104. package/docs/PLUGINS.md +59 -0
  105. package/docs/REAL_WORLD_EXAMPLES.md +109 -0
  106. package/docs/ROADMAP.md +366 -0
  107. package/docs/VALIDATION.md +136 -0
  108. package/eslint.config.cjs +26 -0
  109. package/examples/api-server.ts +254 -0
  110. package/package.json +61 -0
  111. package/src/benchmarks/compare-frameworks.ts +149 -0
  112. package/src/benchmarks/quantam-users.ts +70 -0
  113. package/src/benchmarks/simple-json.ts +71 -0
  114. package/src/benchmarks/ultra-mode.ts +159 -0
  115. package/src/cli/index.ts +214 -0
  116. package/src/client/index.ts +93 -0
  117. package/src/core/batch.ts +110 -0
  118. package/src/core/body-parser.ts +151 -0
  119. package/src/core/buffer-pool.ts +96 -0
  120. package/src/core/config.ts +60 -0
  121. package/src/core/fusion.ts +210 -0
  122. package/src/core/logger.ts +70 -0
  123. package/src/core/metrics.ts +166 -0
  124. package/src/core/resources.ts +38 -0
  125. package/src/core/scheduler.ts +126 -0
  126. package/src/core/scope.ts +87 -0
  127. package/src/core/serializer.ts +41 -0
  128. package/src/core/server.ts +1113 -0
  129. package/src/core/stream.ts +111 -0
  130. package/src/core/tasks.ts +138 -0
  131. package/src/core/types.ts +178 -0
  132. package/src/core/websocket.ts +112 -0
  133. package/src/core/worker-queue.ts +90 -0
  134. package/src/database/adapters/memory.ts +99 -0
  135. package/src/database/adapters/mongo.ts +116 -0
  136. package/src/database/adapters/postgres.ts +86 -0
  137. package/src/database/adapters/sqlite.ts +44 -0
  138. package/src/database/coalescer.ts +153 -0
  139. package/src/database/manager.ts +97 -0
  140. package/src/database/types.ts +24 -0
  141. package/src/index.ts +42 -0
  142. package/src/middleware/compression.ts +147 -0
  143. package/src/middleware/cors.ts +98 -0
  144. package/src/middleware/presets.ts +50 -0
  145. package/src/middleware/rate-limit.ts +106 -0
  146. package/src/middleware/security.ts +109 -0
  147. package/src/middleware/static.ts +216 -0
  148. package/src/openapi/generator.ts +167 -0
  149. package/src/router/radix-router.ts +119 -0
  150. package/src/router/radix-tree.ts +106 -0
  151. package/src/router/router.ts +190 -0
  152. package/src/testing/index.ts +104 -0
  153. package/src/utils/cookies.ts +67 -0
  154. package/src/utils/logger.ts +59 -0
  155. package/src/utils/signals.ts +45 -0
  156. package/src/utils/sse.ts +41 -0
  157. package/src/validation/index.ts +3 -0
  158. package/src/validation/simple.ts +93 -0
  159. package/src/validation/types.ts +38 -0
  160. package/src/validation/zod.ts +14 -0
  161. package/src/views/index.ts +1 -0
  162. package/src/views/types.ts +4 -0
  163. package/tests/adapters.test.ts +120 -0
  164. package/tests/batch.test.ts +139 -0
  165. package/tests/body-parser.test.ts +83 -0
  166. package/tests/compression-sse.test.ts +98 -0
  167. package/tests/cookies.test.ts +74 -0
  168. package/tests/cors.test.ts +79 -0
  169. package/tests/database.test.ts +90 -0
  170. package/tests/dx.test.ts +78 -0
  171. package/tests/ecosystem.test.ts +156 -0
  172. package/tests/features.test.ts +51 -0
  173. package/tests/fusion.test.ts +121 -0
  174. package/tests/http-basic.test.ts +161 -0
  175. package/tests/logger.test.ts +48 -0
  176. package/tests/middleware.test.ts +137 -0
  177. package/tests/observability.test.ts +91 -0
  178. package/tests/openapi.test.ts +74 -0
  179. package/tests/plugin.test.ts +85 -0
  180. package/tests/plugins.test.ts +93 -0
  181. package/tests/rate-limit.test.ts +97 -0
  182. package/tests/resources.test.ts +64 -0
  183. package/tests/scheduler.test.ts +71 -0
  184. package/tests/schema-routes.test.ts +89 -0
  185. package/tests/security.test.ts +128 -0
  186. package/tests/server-db.test.ts +72 -0
  187. package/tests/smoke.test.ts +9 -0
  188. package/tests/sqlite-fusion.test.ts +106 -0
  189. package/tests/static.test.ts +111 -0
  190. package/tests/stream.test.ts +58 -0
  191. package/tests/task-metrics.test.ts +78 -0
  192. package/tests/tasks.test.ts +90 -0
  193. package/tests/testing.test.ts +53 -0
  194. package/tests/validation.test.ts +126 -0
  195. package/tests/websocket.test.ts +132 -0
  196. package/tsconfig.json +16 -0
  197. package/vitest.config.ts +9 -0
@@ -0,0 +1,142 @@
1
+ # Database Engine & Query Fusion
2
+
3
+ QHTTPX includes a powerful, built-in database engine designed for high performance and flexibility. It features a multi-database adapter system, connection pooling, and a unique **Query Fusion** engine that automatically optimizes high-concurrency workloads.
4
+
5
+ ## Features
6
+
7
+ - **Multi-Database Support**: Connect to PostgreSQL, MongoDB, SQLite, and more using a unified API.
8
+ - **Dynamic Adapters**: Drivers (`pg`, `mongodb`) are optional. The framework only loads what you use.
9
+ - **Query Fusion**: Automatically merges identical queries (e.g., `SELECT * FROM users WHERE id = ?`) into single batched queries (e.g., `WHERE id IN (...)`) to reduce network roundtrips.
10
+ - **Batch Execution**: Send multiple operations in a single HTTP request.
11
+ - **Context Integration**: Access database connections directly from your route handlers via `ctx.db`.
12
+
13
+ ## Installation
14
+
15
+ The core framework is lightweight. Install the driver for the database you intend to use:
16
+
17
+ ```bash
18
+ # For PostgreSQL
19
+ npm install pg
20
+
21
+ # For MongoDB
22
+ npm install mongodb
23
+ ```
24
+
25
+ ## Basic Usage
26
+
27
+ ### 1. Configure the Server
28
+
29
+ Initialize the `DatabaseManager` and pass it to your QHTTPX application.
30
+
31
+ ```typescript
32
+ import { createHttpApp } from 'qhttpx';
33
+ import { DatabaseManager } from 'qhttpx/database';
34
+
35
+ const db = new DatabaseManager({
36
+ default: 'main',
37
+ connections: {
38
+ main: {
39
+ type: 'postgres',
40
+ host: 'localhost',
41
+ port: 5432,
42
+ username: 'user',
43
+ password: 'password',
44
+ database: 'mydb'
45
+ }
46
+ }
47
+ });
48
+
49
+ const app = createHttpApp({ db });
50
+
51
+ // Connect during startup
52
+ await app.listen(3000);
53
+ ```
54
+
55
+ ### 2. Accessing the Database in Routes
56
+
57
+ Use `ctx.db.get()` to retrieve the active connection.
58
+
59
+ ```typescript
60
+ app.get('/users/:id', async (ctx) => {
61
+ const db = ctx.db.get('main');
62
+ const userId = ctx.params.id;
63
+
64
+ // Standard Query
65
+ const users = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
66
+
67
+ return ctx.json(users[0]);
68
+ });
69
+ ```
70
+
71
+ ## Bring Your Own Connection
72
+
73
+ If you have a pre-initialized database connection (e.g., from an external library or legacy code), you can register it manually without using the built-in configuration.
74
+
75
+ ```typescript
76
+ import { Client } from 'pg';
77
+ import { PostgresAdapter } from 'qhttpx/database';
78
+
79
+ // 1. Initialize your connection externally
80
+ const client = new Client({ connectionString: process.env.DATABASE_URL });
81
+ await client.connect();
82
+
83
+ // 2. Wrap it in an adapter
84
+ const adapter = new PostgresAdapter({});
85
+ // Note: You'll need to set the internal pool/client manually if bypassing connect()
86
+ // Or simply let QHTTPX manage the connection for you.
87
+
88
+ // 3. Register it
89
+ db.registerConnection('legacy_db', adapter);
90
+ ```
91
+
92
+ ## Query Fusion & Batching
93
+
94
+ The "Killer Feature" of QHTTPX is its ability to coalesce multiple individual requests into a single database query.
95
+
96
+ ### How it works
97
+
98
+ 1. **Client** sends a batch of operations:
99
+ ```json
100
+ POST /batch
101
+ {
102
+ "ops": [
103
+ { "id": "req1", "type": "getUser", "args": [1] },
104
+ { "id": "req2", "type": "getUser", "args": [2] },
105
+ { "id": "req3", "type": "getUser", "args": [3] }
106
+ ]
107
+ }
108
+ ```
109
+
110
+ 2. **Server** defines a coalescing resolver:
111
+ ```typescript
112
+ import { QueryCoalescer } from 'qhttpx/database';
113
+
114
+ const userCoalescer = new QueryCoalescer(async (ids) => {
115
+ // This runs ONCE for the entire batch
116
+ return await db.query('SELECT * FROM users WHERE id = ANY($1)', [ids]);
117
+ });
118
+
119
+ app.op('getUser', async (id) => {
120
+ return await userCoalescer.execute(id);
121
+ });
122
+ ```
123
+
124
+ 3. **Result**: Instead of 3 separate DB queries, QHTTPX executes **1 query**. The results are automatically distributed back to the correct original requests.
125
+
126
+ ## Supported Databases
127
+
128
+ | Database | Adapter Type | Driver Required |
129
+ | :--- | :--- | :--- |
130
+ | **PostgreSQL** | `postgres` | `npm install pg` |
131
+ | **MongoDB** | `mongo` | `npm install mongodb` |
132
+ | **Memory** | `memory` | *(Built-in)* |
133
+
134
+ ## API Reference
135
+
136
+ ### `DatabaseManager`
137
+
138
+ - `constructor(config: DatabaseEngineOptions)`
139
+ - `registerAdapter(type: string, adapter: AdapterConstructor)`: Register custom adapters.
140
+ - `registerConnection(name: string, adapter: DatabaseAdapter)`: Register initialized connections.
141
+ - `connect(name?: string)`: Connect to a specific or default DB.
142
+ - `get(name?: string)`: Get an active adapter instance.
@@ -0,0 +1,146 @@
1
+ # SaaS & Ecosystem Integration Guide
2
+
3
+ QHTTPX is designed as a **Universal Runtime**. It provides a high-performance core but imposes **zero restrictions** on the libraries you choose to build your application.
4
+
5
+ If you are building a SaaS (e.g., a Notion clone), you will likely need specialized tools for Authentication, Caching, and Database management. QHTTPX integrates seamlessly with the standard Node.js ecosystem.
6
+
7
+ ## 🔓 Authentication (JWT / OAuth)
8
+ QHTTPX does not ship with a built-in auth strategy (like Passport) to keep the core lightweight. Instead, it exposes the `ctx` object, allowing you to use libraries like `jose`, `jsonwebtoken`, or `oslo` easily.
9
+
10
+ ### Example: JWT Auth with `jose`
11
+ You can install `jose` (`npm install jose`) and write a simple middleware:
12
+
13
+ ```typescript
14
+ import { createRemoteJWKSet, jwtVerify } from 'jose';
15
+ import { QHTTPXMiddleware } from 'qhttpx';
16
+
17
+ const JWKS = createRemoteJWKSet(new URL('https://your-auth-provider/.well-known/jwks.json'));
18
+
19
+ export const authMiddleware: QHTTPXMiddleware = async (ctx, next) => {
20
+ const authHeader = ctx.req.headers['authorization'];
21
+
22
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
23
+ ctx.res.statusCode = 401;
24
+ ctx.res.end('Unauthorized');
25
+ return;
26
+ }
27
+
28
+ try {
29
+ const token = authHeader.split(' ')[1];
30
+ const { payload } = await jwtVerify(token, JWKS);
31
+
32
+ // Attach user to context state
33
+ ctx.state.user = payload;
34
+
35
+ await next();
36
+ } catch (err) {
37
+ ctx.res.statusCode = 403;
38
+ ctx.res.end('Forbidden');
39
+ }
40
+ };
41
+
42
+ // Usage
43
+ app.use(authMiddleware);
44
+ app.get('/dashboard', (ctx) => {
45
+ const userId = ctx.state.user.sub;
46
+ ctx.json({ message: `Hello ${userId}` });
47
+ });
48
+ ```
49
+
50
+ ## ⚡ Caching (Redis / Memcached)
51
+ For high-scale SaaS, you often need a shared cache layer. QHTTPX's middleware pipeline allows you to intercept requests and serve from cache before hitting your database.
52
+
53
+ ### Example: Redis Caching with `ioredis`
54
+ Install `ioredis` (`npm install ioredis`):
55
+
56
+ ```typescript
57
+ import Redis from 'ioredis';
58
+ import { QHTTPXMiddleware } from 'qhttpx';
59
+
60
+ const redis = new Redis(process.env.REDIS_URL);
61
+
62
+ export const redisCache: QHTTPXMiddleware = async (ctx, next) => {
63
+ if (ctx.req.method !== 'GET') return next();
64
+
65
+ const key = `cache:${ctx.url.pathname}`;
66
+ const cached = await redis.get(key);
67
+
68
+ if (cached) {
69
+ ctx.res.setHeader('X-Cache', 'HIT');
70
+ ctx.res.setHeader('Content-Type', 'application/json');
71
+ ctx.res.end(cached);
72
+ return;
73
+ }
74
+
75
+ // Hook into response to cache the result
76
+ const originalJson = ctx.json;
77
+ ctx.json = (body, status) => {
78
+ // Save to Redis (expire in 60s)
79
+ redis.setex(key, 60, JSON.stringify(body));
80
+ originalJson(body, status);
81
+ };
82
+
83
+ await next();
84
+ };
85
+ ```
86
+
87
+ ## 🗄️ Database (Prisma / Drizzle / TypeORM)
88
+ QHTTPX is database-agnostic. You can use any ORM or Query Builder.
89
+
90
+ ### Example: Using Prisma
91
+ 1. `npm install prisma @prisma/client`
92
+ 2. `npx prisma init`
93
+
94
+ ```typescript
95
+ import { PrismaClient } from '@prisma/client';
96
+ import { QHTTPX } from 'qhttpx';
97
+
98
+ const prisma = new PrismaClient();
99
+ const app = new QHTTPX();
100
+
101
+ // Inject prisma into context (optional, or just import global)
102
+ app.use(async (ctx, next) => {
103
+ ctx.state.db = prisma;
104
+ await next();
105
+ });
106
+
107
+ app.get('/users', async (ctx) => {
108
+ const users = await prisma.user.findMany();
109
+ ctx.json(users);
110
+ });
111
+ ```
112
+
113
+ ## 📦 File Uploads to S3
114
+ While QHTTPX supports `multipart/form-data` parsing locally via `ctx.files`, for a SaaS you typically stream directly to S3.
115
+
116
+ You can use `@aws-sdk/client-s3` inside a handler:
117
+
118
+ ```typescript
119
+ import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
120
+
121
+ const s3 = new S3Client({ region: 'us-east-1' });
122
+
123
+ app.post('/upload', async (ctx) => {
124
+ // Use busboy stream from QHTTPX (advanced) or just buffer
125
+ const file = ctx.files?.['avatar'];
126
+
127
+ await s3.send(new PutObjectCommand({
128
+ Bucket: 'my-saas-bucket',
129
+ Key: `avatars/${Date.now()}_${file.name}`,
130
+ Body: file.data
131
+ }));
132
+
133
+ ctx.json({ success: true });
134
+ });
135
+ ```
136
+
137
+ ## Summary
138
+ | Requirement | Recommended Tool | QHTTPX Integration |
139
+ | :--- | :--- | :--- |
140
+ | **Auth** | `jose`, `jsonwebtoken`, `lucia` | Middleware + `ctx.state.user` |
141
+ | **Database** | `prisma`, `drizzle-orm`, `mongoose` | Import globally or attach to `ctx` |
142
+ | **Caching** | `ioredis`, `node-cache` | Middleware interceptor |
143
+ | **Validation** | `zod`, `valibot` | Native `ctx.validate(schema)` support |
144
+ | **Email** | `resend`, `nodemailer` | Call directly in handlers |
145
+
146
+ **Verdict**: Yes, you have full freedom to install and use any NPM package. QHTTPX acts as the high-performance glue holding your stack together.
@@ -0,0 +1,99 @@
1
+ # The Path to "The Best Framework"
2
+
3
+ To compete with frameworks like Fastify, Hono, and NestJS, QHTTPX needs to master **Type Safety**, **Performance (Serialization)**, and **Observability**.
4
+
5
+ Here is the vision for the final version.
6
+
7
+ ## 1. Type-Safe Validation (Zod Integration)
8
+
9
+ Currently, we use simple strings. The "Best" version integrates **Zod** for TypeScript inference.
10
+
11
+ ```typescript
12
+ import { z } from 'zod';
13
+
14
+ const UserSchema = z.object({
15
+ username: z.string().min(3),
16
+ email: z.string().email(),
17
+ age: z.number().optional()
18
+ });
19
+
20
+ app.post('/users', async (ctx) => {
21
+ // 1. Validates body against Zod schema
22
+ // 2. Throws 400 if invalid
23
+ // 3. 'body' is fully typed as { username: string, email: string, ... }
24
+ const body = await ctx.validate(UserSchema);
25
+
26
+ // No need for "as string" casting
27
+ console.log(body.email);
28
+ });
29
+ ```
30
+
31
+ ## 2. JIT Response Serialization (Performance)
32
+
33
+ `JSON.stringify` is slow. The "Best" frameworks compile schemas to code (JIT). This makes responses 2x-3x faster.
34
+
35
+ ```typescript
36
+ const ResponseSchema = z.object({
37
+ id: z.number(),
38
+ name: z.string(),
39
+ // Exclude 'password' automatically
40
+ });
41
+
42
+ app.get('/users/:id', async (ctx) => {
43
+ const user = await db.getUser(ctx.params.id);
44
+
45
+ // Uses a pre-compiled serializer function
46
+ // Faster than JSON.stringify and safer (strips sensitive fields)
47
+ ctx.schema(ResponseSchema).json(user);
48
+ });
49
+ ```
50
+
51
+ ## 3. Automatic OpenAPI (Swagger) Generation
52
+
53
+ Since we have schemas, we can generate documentation automatically.
54
+
55
+ ```typescript
56
+ // Auto-generate OpenAPI v3 spec from routes and Zod schemas
57
+ app.get('/openapi.json', (ctx) => {
58
+ ctx.json(app.getOpenAPISpec());
59
+ });
60
+
61
+ // Serve Swagger UI
62
+ app.get('/docs', swaggerUI({ url: '/openapi.json' }));
63
+ ```
64
+
65
+ ## 4. End-to-End Type Safety (RPC Client)
66
+
67
+ Share types between Backend and Frontend.
68
+
69
+ ```typescript
70
+ // Shared Types (libs/types.ts)
71
+ export type AppType = typeof app;
72
+
73
+ // Frontend (client.ts)
74
+ import { hc } from 'qhttpx/client';
75
+ import type { AppType } from './server';
76
+
77
+ const client = hc<AppType>('http://localhost:3000');
78
+
79
+ // Fully typed!
80
+ // TypeScript knows that res.json() returns { id: number, name: string }
81
+ const res = await client.users[':id'].$get({
82
+ param: { id: '123' }
83
+ });
84
+ ```
85
+
86
+ ## 5. Structured Logging (Observability)
87
+
88
+ Replace `console.log` with a high-performance JSON logger (like Pino) for production observability.
89
+
90
+ ```typescript
91
+ // Logs: {"level":"info","time":1630000000,"reqId":"req-1","msg":"Request completed","duration":12}
92
+ app.log.info({ userId: 1 }, 'User logged in');
93
+ ```
94
+
95
+ ## Summary of Remaining Work
96
+
97
+ 1. **Validator Upgrade**: Replace `SimpleValidator` with a `ZodValidator`.
98
+ 2. **Serializer Compiler**: Implement `fast-json-stringify` logic.
99
+ 3. **Type Extraction**: Build the `AppType` export logic.
@@ -0,0 +1,99 @@
1
+ # OpenAPI Generation
2
+
3
+ QHTTPX can automatically generate an OpenAPI 3.0 specification from your route definitions and schemas. This allows you to easily create interactive documentation (Swagger UI) for your API.
4
+
5
+ ## Features
6
+
7
+ - **Auto-Discovery**: Scans your router to find all registered endpoints.
8
+ - **Schema Mapping**: Converts your `SimpleValidator` schemas into OpenAPI Schema Objects.
9
+ - **Parameter Inference**: Automatically detects URL parameters (e.g., `/users/:id`) and query parameters.
10
+ - **Zero Configuration**: Just call `app.getOpenAPI()`.
11
+
12
+ ## Usage
13
+
14
+ ### 1. Define Routes with Schemas
15
+
16
+ To get the most out of OpenAPI, define schemas for your routes.
17
+
18
+ ```typescript
19
+ app.post('/users/:id', {
20
+ schema: {
21
+ params: {
22
+ type: 'object',
23
+ properties: {
24
+ id: { type: 'string' }
25
+ }
26
+ },
27
+ body: {
28
+ type: 'object',
29
+ properties: {
30
+ name: { type: 'string', min: 3 },
31
+ email: { type: 'string', pattern: '^\\S+@\\S+\\.\\S+$' }
32
+ },
33
+ required: true
34
+ },
35
+ response: {
36
+ type: 'object',
37
+ properties: {
38
+ success: { type: 'boolean' },
39
+ id: { type: 'string' }
40
+ }
41
+ }
42
+ },
43
+ handler: (ctx) => { /* ... */ }
44
+ });
45
+ ```
46
+
47
+ ### 2. Expose the Spec
48
+
49
+ Create a route to serve the JSON specification.
50
+
51
+ ```typescript
52
+ app.get('/swagger.json', (ctx) => {
53
+ const spec = app.getOpenAPI({
54
+ info: {
55
+ title: 'My Awesome API',
56
+ version: '1.0.0',
57
+ description: 'Powered by QHTTPX'
58
+ },
59
+ servers: [
60
+ { url: 'http://localhost:3000', description: 'Local Server' }
61
+ ]
62
+ });
63
+
64
+ ctx.json(spec);
65
+ });
66
+ ```
67
+
68
+ ### 3. (Optional) Serve Swagger UI
69
+
70
+ You can easily serve a Swagger UI page that points to your spec.
71
+
72
+ ```typescript
73
+ app.get('/docs', (ctx) => {
74
+ ctx.html(`
75
+ <!DOCTYPE html>
76
+ <html lang="en">
77
+ <head>
78
+ <meta charset="utf-8" />
79
+ <title>API Documentation</title>
80
+ <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui.css" />
81
+ </head>
82
+ <body>
83
+ <div id="swagger-ui"></div>
84
+ <script src="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-bundle.js"></script>
85
+ <script>
86
+ window.onload = () => {
87
+ window.ui = SwaggerUIBundle({
88
+ url: '/swagger.json',
89
+ dom_id: '#swagger-ui',
90
+ });
91
+ };
92
+ </script>
93
+ </body>
94
+ </html>
95
+ `);
96
+ });
97
+ ```
98
+
99
+ Now open `http://localhost:3000/docs` to see your interactive API documentation!
@@ -0,0 +1,59 @@
1
+ # QHTTPX Plugin System
2
+
3
+ The QHTTPX Plugin System allows you to encapsulate and share functionality, routes, and middleware. Plugins are fully typed and support scoped routing.
4
+
5
+ ## Creating a Plugin
6
+
7
+ A plugin is simply a function that accepts a `QHTTPXScope` and an options object.
8
+
9
+ ```typescript
10
+ import { QHTTPXPlugin, QHTTPXScope } from 'qhttpx';
11
+
12
+ type MyPluginOptions = {
13
+ secret: string;
14
+ };
15
+
16
+ const myPlugin: QHTTPXPlugin<MyPluginOptions> = async (scope, options) => {
17
+ // Register routes within this scope
18
+ scope.get('/info', (ctx) => {
19
+ ctx.json({ secret: options.secret });
20
+ });
21
+
22
+ // Register sub-plugins
23
+ // await scope.register(otherPlugin);
24
+ };
25
+ ```
26
+
27
+ ## Registering a Plugin
28
+
29
+ Use `app.register()` to load a plugin. You can optionally provide a `prefix` to namespace all routes within the plugin.
30
+
31
+ ```typescript
32
+ import { createHttpApp } from 'qhttpx';
33
+ import { myPlugin } from './my-plugin';
34
+
35
+ const app = createHttpApp();
36
+
37
+ // Routes will be available at /api/v1/info
38
+ await app.register(myPlugin, {
39
+ prefix: '/api/v1',
40
+ secret: 'super-secret'
41
+ });
42
+ ```
43
+
44
+ ## Scope API
45
+
46
+ The `scope` object passed to the plugin exposes standard routing methods:
47
+
48
+ - `scope.get(path, handler)`
49
+ - `scope.post(path, handler)`
50
+ - `scope.put(path, handler)`
51
+ - `scope.delete(path, handler)`
52
+ - `scope.use(middleware)` (Currently global, scoped middleware coming soon)
53
+ - `scope.register(plugin, options)`
54
+
55
+ ## Best Practices
56
+
57
+ 1. **Encapsulation**: Keep plugins self-contained. Avoid relying on global state.
58
+ 2. **Options**: Use the `options` object to pass configuration (database connections, secrets, etc.).
59
+ 3. **Async**: Plugins can be async. QHTTPX will await them during registration.
@@ -0,0 +1,109 @@
1
+ # Real World Usage Examples
2
+
3
+ Here is how QHTTPX looks in a production application.
4
+
5
+ ## 1. The Entry Point (`src/index.ts`)
6
+
7
+ Clean setup with built-in clustering and rate limiting.
8
+
9
+ ```typescript
10
+ import { createHttpApp } from 'qhttpx';
11
+ import { rateLimit } from 'qhttpx/middleware';
12
+
13
+ const app = createHttpApp({
14
+ // Enable built-in request coalescing for high traffic
15
+ enableRequestFusion: true,
16
+ // Auto-scale to CPU cores
17
+ workers: 'auto'
18
+ });
19
+
20
+ // Global Rate Limiter (Aegis)
21
+ app.use(rateLimit({
22
+ windowMs: 60 * 1000,
23
+ max: 1000,
24
+ keyGenerator: (req) => req.headers['x-api-key'] || req.ip
25
+ }));
26
+
27
+ // Start server
28
+ app.listen(3000).then(({ port }) => {
29
+ console.log(`🚀 Server running on port ${port}`);
30
+ });
31
+ ```
32
+
33
+ ## 2. Modular Features (`src/modules/users.ts`)
34
+
35
+ Using the Plugin System to organize code.
36
+
37
+ ```typescript
38
+ import { QHTTPXPlugin, QHTTPXScope } from 'qhttpx';
39
+
40
+ export const userModule: QHTTPXPlugin = async (scope: QHTTPXScope) => {
41
+
42
+ // GET /api/v1/users/:id
43
+ scope.get('/:id', async (ctx) => {
44
+ const userId = ctx.params.id;
45
+ // Auto-fused database query
46
+ const user = await ctx.db.query('SELECT * FROM users WHERE id = ?', [userId]);
47
+
48
+ if (!user) return ctx.notFound();
49
+ ctx.json(user);
50
+ });
51
+
52
+ // POST /api/v1/users
53
+ scope.post('/', async (ctx) => {
54
+ // Built-in validation
55
+ const body = await ctx.validate({
56
+ email: 'string|required',
57
+ age: 'number|min:18'
58
+ });
59
+
60
+ // ... save user logic
61
+ ctx.json({ success: true });
62
+ });
63
+ };
64
+ ```
65
+
66
+ ## 3. Registering Modules (`src/app.ts`)
67
+
68
+ Bringing it all together with prefixes.
69
+
70
+ ```typescript
71
+ import { userModule } from './modules/users';
72
+ import { authModule } from './modules/auth';
73
+
74
+ // Register plugins with prefixes
75
+ await app.register(userModule, { prefix: '/api/v1/users' });
76
+ await app.register(authModule, { prefix: '/api/v1/auth' });
77
+ ```
78
+
79
+ ## 4. High-Performance Query Fusion
80
+
81
+ How the fusion engine simplifies code while boosting performance.
82
+
83
+ ```typescript
84
+ // In your controller/handler:
85
+ // You write simple queries:
86
+ const user = await db.query('SELECT * FROM users WHERE id = ?', [1]);
87
+
88
+ // QHTTPX automatically batches them into:
89
+ // SELECT * FROM users WHERE id IN (1, 2, 3, ...)
90
+ // And distributes the results back to each request.
91
+ ```
92
+
93
+ ## 5. Middleware & Guards
94
+
95
+ Protecting routes is simple.
96
+
97
+ ```typescript
98
+ const adminGuard = (ctx, next) => {
99
+ if (ctx.req.headers['x-role'] !== 'admin') {
100
+ return ctx.status(403).json({ error: 'Forbidden' });
101
+ }
102
+ return next();
103
+ };
104
+
105
+ // Apply to specific route
106
+ app.delete('/db/drop', adminGuard, (ctx) => {
107
+ // ...
108
+ });
109
+ ```