qhttpx 1.8.4 → 1.8.11
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/CHANGELOG.md +59 -0
- package/README.md +72 -52
- package/binding.gyp +18 -0
- package/dist/examples/api-server.js +29 -8
- package/dist/examples/basic.d.ts +1 -0
- package/dist/examples/basic.js +10 -0
- package/dist/examples/compression.d.ts +1 -0
- package/dist/examples/compression.js +17 -0
- package/dist/examples/cors.d.ts +1 -0
- package/dist/examples/cors.js +19 -0
- package/dist/examples/errors.d.ts +1 -0
- package/dist/examples/errors.js +25 -0
- package/dist/examples/file-upload.d.ts +1 -0
- package/dist/examples/file-upload.js +24 -0
- package/dist/examples/fusion.d.ts +1 -0
- package/dist/examples/fusion.js +21 -0
- package/dist/examples/rate-limiting.d.ts +1 -0
- package/dist/examples/rate-limiting.js +17 -0
- package/dist/examples/validation.d.ts +1 -0
- package/dist/examples/validation.js +23 -0
- package/dist/examples/websockets.d.ts +1 -0
- package/dist/examples/websockets.js +20 -0
- package/dist/package.json +12 -1
- package/dist/src/benchmarks/simple-json.js +6 -4
- package/dist/src/cli/index.js +33 -11
- package/dist/src/core/errors.d.ts +34 -0
- package/dist/src/core/errors.js +70 -0
- package/dist/src/core/native-adapter.d.ts +11 -0
- package/dist/src/core/native-adapter.js +211 -0
- package/dist/src/core/server.d.ts +52 -4
- package/dist/src/core/server.js +390 -259
- package/dist/src/core/types.d.ts +39 -1
- package/dist/src/index.d.ts +6 -1
- package/dist/src/index.js +19 -3
- package/dist/src/middleware/compression.d.ts +1 -5
- package/dist/src/middleware/cors.d.ts +1 -10
- package/dist/src/middleware/presets.d.ts +4 -1
- package/dist/src/middleware/presets.js +22 -3
- package/dist/src/middleware/rate-limit.d.ts +1 -19
- package/dist/src/middleware/rate-limit.js +6 -0
- package/dist/src/middleware/security.d.ts +1 -2
- package/dist/src/native/index.d.ts +29 -0
- package/dist/src/native/index.js +64 -0
- package/dist/src/router/radix-tree.d.ts +2 -0
- package/dist/src/router/radix-tree.js +54 -4
- package/dist/src/router/router.d.ts +1 -0
- package/dist/src/router/router.js +42 -2
- package/dist/tests/native-adapter.test.d.ts +1 -0
- package/dist/tests/native-adapter.test.js +71 -0
- package/dist/tests/resources.test.js +3 -0
- package/dist/tests/security.test.js +2 -2
- package/docs/AEGIS.md +34 -9
- package/docs/BENCHMARKS.md +8 -7
- package/docs/ERRORS.md +112 -0
- package/docs/FUSION.md +68 -0
- package/docs/MIDDLEWARE.md +65 -0
- package/docs/ROUTING.md +70 -0
- package/docs/STATIC.md +61 -0
- package/docs/WEBSOCKETS.md +76 -0
- package/package.json +12 -1
- package/src/native/README.md +31 -0
- package/src/native/addon.cc +8 -0
- package/src/native/index.ts +78 -0
- package/src/native/picohttpparser.c +608 -0
- package/src/native/picohttpparser.h +71 -0
- package/src/native/server.cc +262 -0
- package/src/native/server.h +30 -0
- package/.eslintrc.json +0 -22
- package/.github/workflows/ci.yml +0 -32
- package/.github/workflows/npm-publish.yml +0 -37
- package/.github/workflows/release.yml +0 -21
- package/.prettierrc +0 -7
- package/assets/logo.svg +0 -25
- package/eslint.config.cjs +0 -26
- package/examples/api-server.ts +0 -62
- package/src/benchmarks/quantam-users.ts +0 -70
- package/src/benchmarks/simple-json.ts +0 -71
- package/src/benchmarks/ultra-mode.ts +0 -127
- package/src/cli/index.ts +0 -214
- package/src/client/index.ts +0 -93
- package/src/core/batch.ts +0 -110
- package/src/core/body-parser.ts +0 -151
- package/src/core/buffer-pool.ts +0 -96
- package/src/core/config.ts +0 -60
- package/src/core/fusion.ts +0 -210
- package/src/core/logger.ts +0 -70
- package/src/core/metrics.ts +0 -166
- package/src/core/resources.ts +0 -38
- package/src/core/scheduler.ts +0 -126
- package/src/core/scope.ts +0 -87
- package/src/core/serializer.ts +0 -41
- package/src/core/server.ts +0 -1231
- package/src/core/stream.ts +0 -111
- package/src/core/tasks.ts +0 -138
- package/src/core/types.ts +0 -191
- package/src/core/websocket.ts +0 -112
- package/src/core/worker-queue.ts +0 -90
- package/src/database/adapters/memory.ts +0 -99
- package/src/database/adapters/mongo.ts +0 -116
- package/src/database/adapters/postgres.ts +0 -86
- package/src/database/adapters/sqlite.ts +0 -44
- package/src/database/coalescer.ts +0 -153
- package/src/database/manager.ts +0 -97
- package/src/database/types.ts +0 -24
- package/src/index.ts +0 -58
- package/src/middleware/compression.ts +0 -147
- package/src/middleware/cors.ts +0 -98
- package/src/middleware/presets.ts +0 -50
- package/src/middleware/rate-limit.ts +0 -106
- package/src/middleware/security.ts +0 -109
- package/src/middleware/static.ts +0 -216
- package/src/openapi/generator.ts +0 -167
- package/src/router/radix-router.ts +0 -119
- package/src/router/radix-tree.ts +0 -106
- package/src/router/router.ts +0 -190
- package/src/testing/index.ts +0 -104
- package/src/utils/cookies.ts +0 -67
- package/src/utils/logger.ts +0 -59
- package/src/utils/signals.ts +0 -45
- package/src/utils/sse.ts +0 -41
- package/src/validation/index.ts +0 -3
- package/src/validation/simple.ts +0 -93
- package/src/validation/types.ts +0 -38
- package/src/validation/zod.ts +0 -14
- package/src/views/index.ts +0 -1
- package/src/views/types.ts +0 -4
- package/tests/adapters.test.ts +0 -120
- package/tests/batch.test.ts +0 -139
- package/tests/body-parser.test.ts +0 -83
- package/tests/compression-sse.test.ts +0 -98
- package/tests/cookies.test.ts +0 -74
- package/tests/cors.test.ts +0 -79
- package/tests/database.test.ts +0 -90
- package/tests/dx.test.ts +0 -130
- package/tests/ecosystem.test.ts +0 -156
- package/tests/features.test.ts +0 -51
- package/tests/fusion.test.ts +0 -121
- package/tests/http-basic.test.ts +0 -161
- package/tests/logger.test.ts +0 -48
- package/tests/middleware.test.ts +0 -137
- package/tests/observability.test.ts +0 -91
- package/tests/openapi.test.ts +0 -74
- package/tests/plugin.test.ts +0 -85
- package/tests/plugins.test.ts +0 -93
- package/tests/rate-limit.test.ts +0 -97
- package/tests/resources.test.ts +0 -64
- package/tests/scheduler.test.ts +0 -71
- package/tests/schema-routes.test.ts +0 -89
- package/tests/security.test.ts +0 -128
- package/tests/server-db.test.ts +0 -72
- package/tests/smoke.test.ts +0 -9
- package/tests/sqlite-fusion.test.ts +0 -106
- package/tests/static.test.ts +0 -111
- package/tests/stream.test.ts +0 -58
- package/tests/task-metrics.test.ts +0 -78
- package/tests/tasks.test.ts +0 -90
- package/tests/testing.test.ts +0 -53
- package/tests/validation.test.ts +0 -126
- package/tests/websocket.test.ts +0 -132
- package/tsconfig.json +0 -17
- package/vitest.config.ts +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,65 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.8.11] - 2026-01-20
|
|
6
|
+
**"The Workflow Fix"**
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
- **CI/CD**: Changed NPM publish trigger from `release: published` to `push: tags` to bypass GITHUB_TOKEN recursion limits.
|
|
10
|
+
|
|
11
|
+
## [1.8.10] - 2026-01-20
|
|
12
|
+
**"The Debug Update"**
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- **CI/CD**: Enabled verbose logging for NPM publish workflow to diagnose registry errors.
|
|
16
|
+
|
|
17
|
+
## [1.8.9] - 2026-01-20
|
|
18
|
+
**"The Publishing Fix"**
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- **NPM Publishing**: Fixed `npm publish` failure ("Hard link is not allowed") by explicitly whitelisting package files in `package.json`.
|
|
22
|
+
|
|
23
|
+
## [1.8.8] - 2026-01-20
|
|
24
|
+
**"The Documentation & Stability Update"**
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
- **Comprehensive Documentation**: Added detailed guides in `docs/` for Routing, Middleware, Errors, Request Fusion, Aegis Rate Limiting, WebSockets, and Static Files.
|
|
28
|
+
- **Documentation Index**: Added a central documentation index to `README.md`.
|
|
29
|
+
- **Feature Comparison**: Expanded `README.md` comparison table to highlight Hybrid Architecture, Request Fusion, and DDoS Protection.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
- **Native Compilation**: Resolved `npm ci` failures on Windows/Linux by fixing macro usage in `picohttpparser.c` and `writev` return handling in `server.cc`.
|
|
33
|
+
- **TypeScript Types**: Fixed `ctx.next` readonly assignment error that prevented middleware destructuring in some environments.
|
|
34
|
+
- **Tests**: Fixed test suite failures in `dx.test.ts` and `resources.test.ts`.
|
|
35
|
+
|
|
36
|
+
## [1.8.6] - 2026-01-20
|
|
37
|
+
**"The Zero-Boilerplate Update"**
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
- **Zero-Config App Creation**: `createHttpApp` now accepts options for `rateLimit`, `cors`, and `compression` to enable them instantly without manual middleware setup.
|
|
41
|
+
- **CLI Scaffolding**: Added `npm create qhttpx` support via the `create-qhttpx` package. Generates a modern, type-safe project with all best practices enabled.
|
|
42
|
+
- **Standardized Errors**: Added `StandardHttpException` hierarchy (e.g., `NotFoundException`, `TooManyRequestsException`) for consistent error handling.
|
|
43
|
+
- **Rate Limit Improvements**: Added `trustProxy` option to `RateLimitOptions` for correct IP detection behind proxies/load balancers.
|
|
44
|
+
- **Context Utilities**: Added `ctx.ip` (remote address) and `ctx.method` (HTTP method) for easier access.
|
|
45
|
+
- **Native Layer Architecture**: Significant C++ and architectural optimizations for high-throughput scaling:
|
|
46
|
+
- **ABI Lock**: Stabilized C++ interface with `WriteResponse` and `CreateJSONResponse` to prevent future breaking changes.
|
|
47
|
+
- **Zero-Copy JSON**: Implemented `createJSONResponse` fast path in C++ for serialization and HTTP framing without V8 transition overhead.
|
|
48
|
+
- **Object Pooling**: Added `MockResponsePool` to recycle request/response objects, reducing Garbage Collection pressure.
|
|
49
|
+
- **CPU Affinity**: Added `setCPUAffinity` to bind processes/threads to specific CPU cores for linear multi-core scaling.
|
|
50
|
+
- **Ultra Performance**: Optimized Ultra Mode with lazy URL parsing and reduced overhead, achieving >50% reduction in p99 latency (1.4s -> ~0.7s) under heavy load.
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
- **Simplified CLI**: `qhttpx new` now uses the same template as `create-qhttpx`, ensuring consistency.
|
|
54
|
+
- **Dependency Management**: Scaffolding now uses explicit versioning (`^x.y.z`) for stability instead of `latest`.
|
|
55
|
+
- **Benchmarks**: Updated performance comparisons against Fastify, Hono, and Express in `README.md` and `docs/BENCHMARKS.md`.
|
|
56
|
+
|
|
57
|
+
## [1.8.5] - 2026-01-20
|
|
58
|
+
**"The Usability IV Update"**
|
|
59
|
+
|
|
60
|
+
### Added
|
|
61
|
+
- **Context Headers**: Added `ctx.headers` (alias for `req.headers`) for direct access to request headers.
|
|
62
|
+
- **Environment**: Added `dotenv` and updated `@types/node` dependencies.
|
|
63
|
+
|
|
5
64
|
## [1.8.4] - 2026-01-20
|
|
6
65
|
**"The Usability III Update"**
|
|
7
66
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
<img src="https://raw.githubusercontent.com/Quantam-Open-Source/qhttpx/main/assets/logo.svg" alt="QHTTPX Logo" width="200" height="200" />
|
|
3
3
|
</div>
|
|
4
4
|
|
|
5
|
-
<h1 align="center">QHTTPX</h1>
|
|
6
5
|
|
|
7
6
|
<div align="center">
|
|
8
7
|
<strong>The High-Performance Hybrid HTTP Runtime for Node.js</strong>
|
|
@@ -41,6 +40,22 @@ Most Node.js frameworks rely on the event loop blindly. QHTTPX introduces a **Co
|
|
|
41
40
|
| **Routing** | Regex / Linear Scan | **Radix Tree** (O(1) lookup) |
|
|
42
41
|
| **Streaming** | Basic Pipe | **Smart Streams** (Backpressure-aware) |
|
|
43
42
|
|
|
43
|
+
### 🏆 Feature Comparison
|
|
44
|
+
|
|
45
|
+
| Feature | **QHTTPX** | Fastify | Express | Hono |
|
|
46
|
+
| :--- | :---: | :---: | :---: | :---: |
|
|
47
|
+
| **Core Runtime** | **⚡ Hybrid (C++ / JS)** | JS | JS | JS |
|
|
48
|
+
| **Request Fusion** | **✅ Native** | ❌ | ❌ | ❌ |
|
|
49
|
+
| **DDoS Protection** | **✅ Built-in (Aegis)** | ❌ | ❌ | ❌ |
|
|
50
|
+
| **JSON Serialization** | **✅ Zero-Copy (C++)** | Schema-based | Slow | Slow |
|
|
51
|
+
| **Concurrency Model** | **✅ Async Scheduler** | Event Loop | Event Loop | Event Loop |
|
|
52
|
+
| **Rate Limiting** | **✅ Zero-Overhead** | Plugin | Middleware | Middleware |
|
|
53
|
+
| **Routing Algorithm** | **✅ Optimized Radix** | Radix Tree | Linear/Regex | RegExp/Trie |
|
|
54
|
+
| **WebSocket** | **✅ Built-in Pub/Sub** | Plugin | Plugin | Helper |
|
|
55
|
+
| **Multipart Uploads** | **✅ Native** | Plugin | Middleware | Plugin |
|
|
56
|
+
| **Static Assets** | **✅ Smart Streaming** | Standard | Standard | Standard |
|
|
57
|
+
| **Type Safety** | **✅ First-class** | Good | Partial | First-class |
|
|
58
|
+
|
|
44
59
|
---
|
|
45
60
|
|
|
46
61
|
## ✨ Key Features
|
|
@@ -77,7 +92,16 @@ npm install qhttpx
|
|
|
77
92
|
|
|
78
93
|
## ⚡ Quick Start
|
|
79
94
|
|
|
80
|
-
### 1.
|
|
95
|
+
### 1. Create a Project (Recommended)
|
|
96
|
+
|
|
97
|
+
Scaffold a production-ready QHTTPX application instantly using our CLI tool:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm create qhttpx@latest
|
|
101
|
+
```
|
|
102
|
+
This will set up a project with TypeScript, Request Fusion, and best practices pre-configured.
|
|
103
|
+
|
|
104
|
+
### 2. The Rapid Way (Singleton)
|
|
81
105
|
Get up and running instantly with the singleton instance and destructuring support.
|
|
82
106
|
|
|
83
107
|
```typescript
|
|
@@ -95,7 +119,7 @@ app.onError(({ error, json }) => {
|
|
|
95
119
|
app.listen(3000, () => console.log("Server running on http://localhost:3000"));
|
|
96
120
|
```
|
|
97
121
|
|
|
98
|
-
###
|
|
122
|
+
### 3. The Custom Way (Advanced)
|
|
99
123
|
When you need specific configuration options or multiple instances.
|
|
100
124
|
|
|
101
125
|
```typescript
|
|
@@ -115,65 +139,36 @@ app.get("/users", async ({ json, query }) => {
|
|
|
115
139
|
app.listen(3000);
|
|
116
140
|
```
|
|
117
141
|
|
|
118
|
-
### 2. The Scalable Way (Cluster Mode)
|
|
119
|
-
For production workloads utilizing all CPU cores.
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
# Start your app in cluster mode
|
|
123
|
-
npx qhttpx start dist/index.js
|
|
124
|
-
```
|
|
125
|
-
|
|
126
142
|
---
|
|
127
143
|
|
|
128
|
-
##
|
|
129
|
-
|
|
130
|
-
### Request Fusion (The "Magic")
|
|
131
|
-
Enable `enableRequestFusion` to automatically deduplicate traffic.
|
|
132
|
-
|
|
133
|
-
```typescript
|
|
134
|
-
const app = new QHTTPX({
|
|
135
|
-
enableRequestFusion: true
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// If 50 users hit this endpoint simultaneously,
|
|
139
|
-
// the database query runs only ONCE.
|
|
140
|
-
app.get("/heavy-query", async (ctx) => {
|
|
141
|
-
const data = await db.expensiveQuery();
|
|
142
|
-
return ctx.json(data);
|
|
143
|
-
});
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### Real-Time (SSE & WebSockets)
|
|
144
|
+
## 📚 Documentation
|
|
147
145
|
|
|
148
|
-
|
|
149
|
-
// Server-Sent Events
|
|
150
|
-
app.get('/events', (ctx) => {
|
|
151
|
-
const stream = createSSE(ctx);
|
|
152
|
-
setInterval(() => {
|
|
153
|
-
stream.send({ time: Date.now() }, 'tick');
|
|
154
|
-
}, 1000);
|
|
155
|
-
});
|
|
146
|
+
Detailed guides for every feature of QHTTPX:
|
|
156
147
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
```
|
|
148
|
+
- **[Routing](./docs/ROUTING.md)**: Radix tree, parameters, and groups.
|
|
149
|
+
- **[Middleware](./docs/MIDDLEWARE.md)**: Global and route-level hooks.
|
|
150
|
+
- **[Error Handling](./docs/ERRORS.md)**: Standard exceptions and global handlers.
|
|
151
|
+
- **[Aegis Rate Limiter](./docs/AEGIS.md)**: DDoS protection and traffic shaping.
|
|
152
|
+
- **[Request Fusion](./docs/FUSION.md)**: "Thundering Herd" protection engine.
|
|
153
|
+
- **[WebSockets](./docs/WEBSOCKETS.md)**: Real-time Pub/Sub and Rooms.
|
|
154
|
+
- **[Static Files](./docs/STATIC.md)**: Streaming, Range requests, and Caching.
|
|
155
|
+
- **[Ecosystem Integration](./docs/ECOSYSTEM.md)**: Auth, Database, and Validation patterns.
|
|
166
156
|
|
|
167
157
|
---
|
|
168
158
|
|
|
169
159
|
## 📊 Benchmarks
|
|
170
160
|
|
|
171
|
-
|
|
161
|
+
Benchmarks comparing **QHTTPX v1.8.6** against popular Node.js frameworks.
|
|
162
|
+
*(Run on local environment: Windows, 100 connections, 10 pipelining, 40s duration. Average of 2 runs, taking the second result.)*
|
|
172
163
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
164
|
+
| Framework | Req/Sec | Latency (Avg) | Throughput |
|
|
165
|
+
| :--- | :--- | :--- | :--- |
|
|
166
|
+
| **Fastify** | 16,050 | 256.78 ms | 3.00 Mb/s |
|
|
167
|
+
| **QHTTPX** | **14,179** | **291.13 ms** | **3.02 Mb/s** |
|
|
168
|
+
| **Hono** | 14,176 | 294.09 ms | 2.43 Mb/s |
|
|
169
|
+
| **Express** | 10,450 | 407.12 ms | 1.94 Mb/s |
|
|
170
|
+
|
|
171
|
+
> **Note**: QHTTPX achieves comparable throughput to Fastify while offering advanced features like **Request Fusion** (deduplication) which can significantly reduce database load in real-world scenarios.
|
|
177
172
|
|
|
178
173
|
---
|
|
179
174
|
|
|
@@ -187,6 +182,31 @@ QHTTPX is an **Open Runtime**. It works seamlessly with standard tools:
|
|
|
187
182
|
|
|
188
183
|
---
|
|
189
184
|
|
|
185
|
+
## 👥 Team
|
|
186
|
+
|
|
187
|
+
QHTTPX is developed and maintained by **Quantam Open Source**.
|
|
188
|
+
|
|
189
|
+
### Lead Developer
|
|
190
|
+
**Byron Kennedy Pfukwa**
|
|
191
|
+
*Creator & Core Maintainer*
|
|
192
|
+
[](https://github.com/BYRON-lang)
|
|
193
|
+
[](https://www.npmjs.com/~brnxdev)
|
|
194
|
+
[](https://x.com/byronpfukwa)
|
|
195
|
+
|
|
196
|
+
### Socials
|
|
197
|
+
Follow us for updates:
|
|
198
|
+
- **QHTTPX (X)**: [@qhttpx](https://x.com/qhttpx)
|
|
199
|
+
- **Open Quantam (X)**: [@openquantam](https://x.com/openquantam)
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
190
203
|
## 📜 License
|
|
191
204
|
|
|
192
205
|
MIT © [Quantam Open Source](https://github.com/Quantam-Open-Source)
|
|
206
|
+
|
|
207
|
+
<br />
|
|
208
|
+
|
|
209
|
+
<div align="center">
|
|
210
|
+
<p>Project Part of</p>
|
|
211
|
+
<img src="assets/open%20quantam.png" alt="Open Quantam" width="150" />
|
|
212
|
+
</div>
|
package/binding.gyp
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"targets": [
|
|
3
|
+
{
|
|
4
|
+
"target_name": "qhttpx_native",
|
|
5
|
+
"cflags!": [ "-fno-exceptions" ],
|
|
6
|
+
"cflags_cc!": [ "-fno-exceptions" ],
|
|
7
|
+
"sources": [
|
|
8
|
+
"src/native/addon.cc",
|
|
9
|
+
"src/native/server.cc",
|
|
10
|
+
"src/native/picohttpparser.c"
|
|
11
|
+
],
|
|
12
|
+
"include_dirs": [
|
|
13
|
+
"<!@(node -p \"require('node-addon-api').include\")"
|
|
14
|
+
],
|
|
15
|
+
"defines": [ "NAPI_DISABLE_CPP_EXCEPTIONS" ]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const index_1 = require("../src/index");
|
|
4
|
+
const dotenv_1 = require("dotenv");
|
|
5
|
+
// Load .env
|
|
6
|
+
(0, dotenv_1.config)();
|
|
4
7
|
// 1. Initialize App (Fusion + Aegis enabled)
|
|
5
8
|
const app = (0, index_1.createHttpApp)({
|
|
6
9
|
enableRequestFusion: true, // ⚡ Auto-coalesce duplicate requests
|
|
7
|
-
metricsEnabled: true // 📊 Expose /__qhttpx/metrics
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
metricsEnabled: true, // 📊 Expose /__qhttpx/metrics
|
|
11
|
+
rateLimit: {
|
|
12
|
+
windowMs: 15 * 60 * 1000,
|
|
13
|
+
max: 100,
|
|
14
|
+
trustProxy: true
|
|
15
|
+
},
|
|
16
|
+
cors: true, // 🛡️ Built-in CORS
|
|
17
|
+
compression: true // 🗜️ Built-in Compression (Gzip/Brotli)
|
|
14
18
|
});
|
|
19
|
+
// 2. Global Middleware (Logging is built-in by default)
|
|
20
|
+
// No manual app.use(rateLimit(...)) needed!
|
|
15
21
|
// 3. Validation Schema
|
|
16
22
|
const UserSchema = {
|
|
17
23
|
body: {
|
|
@@ -32,7 +38,15 @@ app.post('/users', { schema: UserSchema }, async ({ body, json }) => {
|
|
|
32
38
|
// Body is already validated and typed here
|
|
33
39
|
json({ created: true, user: body }, 201);
|
|
34
40
|
});
|
|
35
|
-
//
|
|
41
|
+
// � Header Auth Example
|
|
42
|
+
app.post('/auth/verify', async ({ headers, json }) => {
|
|
43
|
+
const token = headers.authorization?.replace('Bearer ', '');
|
|
44
|
+
if (!token)
|
|
45
|
+
return json({ error: 'No token provided' }, 401);
|
|
46
|
+
// Verify token...
|
|
47
|
+
json({ valid: true, token });
|
|
48
|
+
});
|
|
49
|
+
// �📂 File Uploads (Typed)
|
|
36
50
|
app.post('/upload', ({ files, json }) => {
|
|
37
51
|
if (!files?.doc)
|
|
38
52
|
return json({ error: 'No file' }, 400);
|
|
@@ -49,6 +63,13 @@ app.upgrade('/chat', (ws) => {
|
|
|
49
63
|
});
|
|
50
64
|
// 5. Unified Error Handling
|
|
51
65
|
app.onError(({ error, json }) => {
|
|
66
|
+
if (error instanceof index_1.HttpError) {
|
|
67
|
+
return json({
|
|
68
|
+
error: error.message,
|
|
69
|
+
code: error.code,
|
|
70
|
+
details: error.details
|
|
71
|
+
}, error.status);
|
|
72
|
+
}
|
|
52
73
|
console.error(error); // Log internal error
|
|
53
74
|
json({ error: 'Internal Server Error', handled: true }, 500);
|
|
54
75
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../src/index");
|
|
4
|
+
const app = (0, index_1.createHttpApp)();
|
|
5
|
+
app.get('/', ({ json }) => {
|
|
6
|
+
json({ message: 'Hello from QHTTPX!' });
|
|
7
|
+
});
|
|
8
|
+
app.listen(3000, () => {
|
|
9
|
+
console.log('Server running on http://localhost:3000');
|
|
10
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../src/index");
|
|
4
|
+
const app = (0, index_1.createHttpApp)({
|
|
5
|
+
// Enable Gzip/Brotli compression
|
|
6
|
+
compression: true
|
|
7
|
+
// Or with options:
|
|
8
|
+
// compression: { threshold: 2048 } // Only compress responses > 2KB
|
|
9
|
+
});
|
|
10
|
+
app.get('/large', ({ json }) => {
|
|
11
|
+
// Generate a large response to trigger compression
|
|
12
|
+
const data = Array(1000).fill('some repeated data to compress');
|
|
13
|
+
json({ data });
|
|
14
|
+
});
|
|
15
|
+
app.listen(3000, () => {
|
|
16
|
+
console.log('Compression-enabled server running on http://localhost:3000');
|
|
17
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../src/index");
|
|
4
|
+
const app = (0, index_1.createHttpApp)({
|
|
5
|
+
// Simple: Enable CORS for all origins
|
|
6
|
+
// cors: true
|
|
7
|
+
// Advanced: Configure specific origins
|
|
8
|
+
cors: {
|
|
9
|
+
origin: ['http://localhost:5173', 'https://myapp.com'],
|
|
10
|
+
methods: ['GET', 'POST'],
|
|
11
|
+
credentials: true
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
app.get('/api/data', ({ json }) => {
|
|
15
|
+
json({ data: 'This data is accessible via CORS' });
|
|
16
|
+
});
|
|
17
|
+
app.listen(3000, () => {
|
|
18
|
+
console.log('CORS-enabled server running on http://localhost:3000');
|
|
19
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../src/index");
|
|
4
|
+
const app = (0, index_1.createHttpApp)();
|
|
5
|
+
app.get('/missing', () => {
|
|
6
|
+
throw new index_1.NotFoundException('Resource not found');
|
|
7
|
+
});
|
|
8
|
+
app.get('/private', () => {
|
|
9
|
+
throw new index_1.ForbiddenException('You do not have access');
|
|
10
|
+
});
|
|
11
|
+
// Custom global error handler
|
|
12
|
+
app.onError(({ error, json }) => {
|
|
13
|
+
if (error instanceof index_1.HttpError) {
|
|
14
|
+
return json({
|
|
15
|
+
status: 'error',
|
|
16
|
+
code: error.code,
|
|
17
|
+
message: error.message
|
|
18
|
+
}, error.status);
|
|
19
|
+
}
|
|
20
|
+
console.error('Unexpected error:', error);
|
|
21
|
+
json({ status: 'error', message: 'Internal Server Error' }, 500);
|
|
22
|
+
});
|
|
23
|
+
app.listen(3000, () => {
|
|
24
|
+
console.log('Error handling demo running on http://localhost:3000');
|
|
25
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../src/index");
|
|
4
|
+
const app = (0, index_1.createHttpApp)({
|
|
5
|
+
// Limits for uploads
|
|
6
|
+
maxBodyBytes: 10 * 1024 * 1024 // 10MB
|
|
7
|
+
});
|
|
8
|
+
app.post('/upload', ({ files, json }) => {
|
|
9
|
+
if (!files || !files.document) {
|
|
10
|
+
return json({ error: 'No file uploaded' }, 400);
|
|
11
|
+
}
|
|
12
|
+
const doc = Array.isArray(files.document) ? files.document[0] : files.document;
|
|
13
|
+
console.log(`Received file: ${doc.filename} (${doc.size} bytes)`);
|
|
14
|
+
json({
|
|
15
|
+
uploaded: true,
|
|
16
|
+
filename: doc.filename,
|
|
17
|
+
mimetype: doc.mimeType,
|
|
18
|
+
size: doc.size
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
app.listen(3000, () => {
|
|
22
|
+
console.log('Upload server running on http://localhost:3000');
|
|
23
|
+
console.log('Send POST to /upload with form-data field "document"');
|
|
24
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../src/index");
|
|
4
|
+
const app = (0, index_1.createHttpApp)({
|
|
5
|
+
// Enable Request Fusion (Request Coalescing)
|
|
6
|
+
enableRequestFusion: true
|
|
7
|
+
});
|
|
8
|
+
// Simulate a slow database call
|
|
9
|
+
const heavyTask = async () => {
|
|
10
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
11
|
+
return { data: 'Expensive Result', timestamp: Date.now() };
|
|
12
|
+
};
|
|
13
|
+
// If 1000 users hit this endpoint simultaneously,
|
|
14
|
+
// the handler runs ONLY ONCE, and the result is shared.
|
|
15
|
+
app.get('/heavy', async ({ json }) => {
|
|
16
|
+
const result = await heavyTask();
|
|
17
|
+
json(result);
|
|
18
|
+
});
|
|
19
|
+
app.listen(3000, () => {
|
|
20
|
+
console.log('Fusion-enabled server running on http://localhost:3000');
|
|
21
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../src/index");
|
|
4
|
+
const app = (0, index_1.createHttpApp)({
|
|
5
|
+
rateLimit: {
|
|
6
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
7
|
+
max: 100, // Limit each IP to 100 requests per window
|
|
8
|
+
message: 'Too many requests, please try again later.',
|
|
9
|
+
trustProxy: true // Trust X-Forwarded-For header (useful behind proxies like Nginx)
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
app.get('/', ({ json }) => {
|
|
13
|
+
json({ status: 'OK', message: 'Request accepted' });
|
|
14
|
+
});
|
|
15
|
+
app.listen(3000, () => {
|
|
16
|
+
console.log('Rate-limited server running on http://localhost:3000');
|
|
17
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../src/index");
|
|
4
|
+
const app = (0, index_1.createHttpApp)();
|
|
5
|
+
// Define a simple schema (or use Zod if configured)
|
|
6
|
+
const UserSchema = {
|
|
7
|
+
body: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
required: ['username', 'email'],
|
|
10
|
+
properties: {
|
|
11
|
+
username: { type: 'string' },
|
|
12
|
+
email: { type: 'string' }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
// Apply schema to route
|
|
17
|
+
app.post('/register', { schema: UserSchema }, ({ body, json }) => {
|
|
18
|
+
// 'body' is already validated and typed here (if using TS with inferred types)
|
|
19
|
+
json({ success: true, user: body });
|
|
20
|
+
});
|
|
21
|
+
app.listen(3000, () => {
|
|
22
|
+
console.log('Validation server running on http://localhost:3000');
|
|
23
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../src/index");
|
|
4
|
+
const app = (0, index_1.createHttpApp)();
|
|
5
|
+
app.upgrade('/chat', (ws) => {
|
|
6
|
+
console.log('Client connected');
|
|
7
|
+
ws.join('general');
|
|
8
|
+
ws.on('message', (msg) => {
|
|
9
|
+
console.log(`Received: ${msg}`);
|
|
10
|
+
// Broadcast to everyone in 'general' room
|
|
11
|
+
app.websocket.to('general').emit(`Echo: ${msg}`);
|
|
12
|
+
});
|
|
13
|
+
ws.on('close', () => {
|
|
14
|
+
console.log('Client disconnected');
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
app.listen(3000, () => {
|
|
18
|
+
console.log('WebSocket Server running on http://localhost:3000');
|
|
19
|
+
console.log('Test with a WebSocket client at ws://localhost:3000/chat');
|
|
20
|
+
});
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qhttpx",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.11",
|
|
4
4
|
"description": "The High-Performance Hybrid HTTP Runtime for Node.js. Built for extreme concurrency, request fusion, and zero-overhead scaling.",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -14,6 +14,15 @@
|
|
|
14
14
|
"bin": {
|
|
15
15
|
"qhttpx": "./dist/src/cli/index.js"
|
|
16
16
|
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"src/native",
|
|
20
|
+
"binding.gyp",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE",
|
|
23
|
+
"CHANGELOG.md",
|
|
24
|
+
"docs"
|
|
25
|
+
],
|
|
17
26
|
"directories": {
|
|
18
27
|
"doc": "docs"
|
|
19
28
|
},
|
|
@@ -67,6 +76,7 @@
|
|
|
67
76
|
"@typescript-eslint/eslint-plugin": "^8.53.0",
|
|
68
77
|
"@typescript-eslint/parser": "^8.53.0",
|
|
69
78
|
"autocannon": "^8.0.0",
|
|
79
|
+
"dotenv": "^17.2.3",
|
|
70
80
|
"eslint": "^9.39.2",
|
|
71
81
|
"eslint-config-prettier": "^10.1.8",
|
|
72
82
|
"eslint-plugin-prettier": "^5.5.5",
|
|
@@ -81,6 +91,7 @@
|
|
|
81
91
|
"better-sqlite3": "^12.6.2",
|
|
82
92
|
"busboy": "^1.6.0",
|
|
83
93
|
"fast-json-stringify": "^5.15.1",
|
|
94
|
+
"node-addon-api": "^8.5.0",
|
|
84
95
|
"pino": "^10.2.0",
|
|
85
96
|
"pino-pretty": "^13.1.3",
|
|
86
97
|
"quantam-async": "^0.1.1",
|
|
@@ -9,10 +9,9 @@ function runAutocannon(url) {
|
|
|
9
9
|
return new Promise((resolve, reject) => {
|
|
10
10
|
const instance = (0, autocannon_1.default)({
|
|
11
11
|
url,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
duration: 10,
|
|
12
|
+
connections: 100,
|
|
13
|
+
pipelining: 10,
|
|
14
|
+
duration: 40,
|
|
16
15
|
}, (err, result) => {
|
|
17
16
|
if (err) {
|
|
18
17
|
reject(err);
|
|
@@ -37,6 +36,9 @@ async function run() {
|
|
|
37
36
|
});
|
|
38
37
|
const { port } = await app.listen(0, '127.0.0.1');
|
|
39
38
|
const url = `http://127.0.0.1:${port}/json`;
|
|
39
|
+
console.log('Running warmup (1/2)...');
|
|
40
|
+
await runAutocannon(url);
|
|
41
|
+
console.log('Running benchmark (2/2)...');
|
|
40
42
|
const result = await runAutocannon(url);
|
|
41
43
|
autocannon_1.default.printResult(result);
|
|
42
44
|
const totalRequests = result.requests.total;
|