qhttpx 1.8.12 → 1.9.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.
- package/package.json +12 -3
- package/prebuilds/darwin-arm64/qhttpx.node +0 -0
- package/prebuilds/linux-x64/qhttpx.node +0 -0
- package/prebuilds/win32-x64/qhttpx.node +0 -0
- package/src/native/index.ts +104 -24
- package/src/native/picohttpparser.h +5 -0
- package/src/native/server.cc +2 -0
- package/dist/examples/api-server.d.ts +0 -1
- package/dist/examples/api-server.js +0 -77
- package/dist/examples/basic.d.ts +0 -1
- package/dist/examples/basic.js +0 -10
- package/dist/examples/compression.d.ts +0 -1
- package/dist/examples/compression.js +0 -17
- package/dist/examples/cors.d.ts +0 -1
- package/dist/examples/cors.js +0 -19
- package/dist/examples/errors.d.ts +0 -1
- package/dist/examples/errors.js +0 -25
- package/dist/examples/file-upload.d.ts +0 -1
- package/dist/examples/file-upload.js +0 -24
- package/dist/examples/fusion.d.ts +0 -1
- package/dist/examples/fusion.js +0 -21
- package/dist/examples/rate-limiting.d.ts +0 -1
- package/dist/examples/rate-limiting.js +0 -17
- package/dist/examples/validation.d.ts +0 -1
- package/dist/examples/validation.js +0 -23
- package/dist/examples/websockets.d.ts +0 -1
- package/dist/examples/websockets.js +0 -20
- package/dist/package.json +0 -101
- package/dist/src/benchmarks/quantam-users.d.ts +0 -1
- package/dist/src/benchmarks/quantam-users.js +0 -56
- package/dist/src/benchmarks/simple-json.d.ts +0 -1
- package/dist/src/benchmarks/simple-json.js +0 -60
- package/dist/src/benchmarks/ultra-mode.d.ts +0 -1
- package/dist/src/benchmarks/ultra-mode.js +0 -94
- package/dist/src/cli/index.d.ts +0 -2
- package/dist/src/cli/index.js +0 -222
- package/dist/src/client/index.d.ts +0 -17
- package/dist/src/client/index.js +0 -72
- package/dist/src/core/batch.d.ts +0 -24
- package/dist/src/core/batch.js +0 -97
- package/dist/src/core/body-parser.d.ts +0 -15
- package/dist/src/core/body-parser.js +0 -121
- package/dist/src/core/buffer-pool.d.ts +0 -41
- package/dist/src/core/buffer-pool.js +0 -70
- package/dist/src/core/config.d.ts +0 -7
- package/dist/src/core/config.js +0 -50
- package/dist/src/core/errors.d.ts +0 -34
- package/dist/src/core/errors.js +0 -70
- package/dist/src/core/fusion.d.ts +0 -14
- package/dist/src/core/fusion.js +0 -183
- package/dist/src/core/logger.d.ts +0 -22
- package/dist/src/core/logger.js +0 -49
- package/dist/src/core/metrics.d.ts +0 -45
- package/dist/src/core/metrics.js +0 -111
- package/dist/src/core/native-adapter.d.ts +0 -11
- package/dist/src/core/native-adapter.js +0 -211
- package/dist/src/core/resources.d.ts +0 -9
- package/dist/src/core/resources.js +0 -25
- package/dist/src/core/scheduler.d.ts +0 -34
- package/dist/src/core/scheduler.js +0 -85
- package/dist/src/core/scope.d.ts +0 -26
- package/dist/src/core/scope.js +0 -68
- package/dist/src/core/serializer.d.ts +0 -10
- package/dist/src/core/serializer.js +0 -44
- package/dist/src/core/server.d.ts +0 -138
- package/dist/src/core/server.js +0 -1082
- package/dist/src/core/stream.d.ts +0 -15
- package/dist/src/core/stream.js +0 -71
- package/dist/src/core/tasks.d.ts +0 -29
- package/dist/src/core/tasks.js +0 -87
- package/dist/src/core/types.d.ts +0 -173
- package/dist/src/core/types.js +0 -19
- package/dist/src/core/websocket.d.ts +0 -25
- package/dist/src/core/websocket.js +0 -86
- package/dist/src/core/worker-queue.d.ts +0 -41
- package/dist/src/core/worker-queue.js +0 -73
- package/dist/src/database/adapters/memory.d.ts +0 -21
- package/dist/src/database/adapters/memory.js +0 -90
- package/dist/src/database/adapters/mongo.d.ts +0 -11
- package/dist/src/database/adapters/mongo.js +0 -141
- package/dist/src/database/adapters/postgres.d.ts +0 -10
- package/dist/src/database/adapters/postgres.js +0 -111
- package/dist/src/database/adapters/sqlite.d.ts +0 -10
- package/dist/src/database/adapters/sqlite.js +0 -42
- package/dist/src/database/coalescer.d.ts +0 -14
- package/dist/src/database/coalescer.js +0 -134
- package/dist/src/database/manager.d.ts +0 -35
- package/dist/src/database/manager.js +0 -87
- package/dist/src/database/types.d.ts +0 -20
- package/dist/src/database/types.js +0 -2
- package/dist/src/index.d.ts +0 -50
- package/dist/src/index.js +0 -91
- package/dist/src/middleware/compression.d.ts +0 -2
- package/dist/src/middleware/compression.js +0 -133
- package/dist/src/middleware/cors.d.ts +0 -2
- package/dist/src/middleware/cors.js +0 -66
- package/dist/src/middleware/presets.d.ts +0 -16
- package/dist/src/middleware/presets.js +0 -52
- package/dist/src/middleware/rate-limit.d.ts +0 -14
- package/dist/src/middleware/rate-limit.js +0 -83
- package/dist/src/middleware/security.d.ts +0 -21
- package/dist/src/middleware/security.js +0 -69
- package/dist/src/middleware/static.d.ts +0 -11
- package/dist/src/middleware/static.js +0 -191
- package/dist/src/native/index.d.ts +0 -29
- package/dist/src/native/index.js +0 -64
- package/dist/src/openapi/generator.d.ts +0 -19
- package/dist/src/openapi/generator.js +0 -149
- package/dist/src/router/radix-router.d.ts +0 -18
- package/dist/src/router/radix-router.js +0 -89
- package/dist/src/router/radix-tree.d.ts +0 -18
- package/dist/src/router/radix-tree.js +0 -131
- package/dist/src/router/router.d.ts +0 -34
- package/dist/src/router/router.js +0 -186
- package/dist/src/testing/index.d.ts +0 -25
- package/dist/src/testing/index.js +0 -84
- package/dist/src/utils/cookies.d.ts +0 -3
- package/dist/src/utils/cookies.js +0 -59
- package/dist/src/utils/logger.d.ts +0 -12
- package/dist/src/utils/logger.js +0 -45
- package/dist/src/utils/signals.d.ts +0 -6
- package/dist/src/utils/signals.js +0 -31
- package/dist/src/utils/sse.d.ts +0 -6
- package/dist/src/utils/sse.js +0 -32
- package/dist/src/validation/index.d.ts +0 -3
- package/dist/src/validation/index.js +0 -19
- package/dist/src/validation/simple.d.ts +0 -5
- package/dist/src/validation/simple.js +0 -102
- package/dist/src/validation/types.d.ts +0 -32
- package/dist/src/validation/types.js +0 -12
- package/dist/src/validation/zod.d.ts +0 -4
- package/dist/src/validation/zod.js +0 -18
- package/dist/src/views/index.d.ts +0 -1
- package/dist/src/views/index.js +0 -17
- package/dist/src/views/types.d.ts +0 -3
- package/dist/src/views/types.js +0 -2
- package/dist/tests/adapters.test.d.ts +0 -1
- package/dist/tests/adapters.test.js +0 -106
- package/dist/tests/batch.test.d.ts +0 -1
- package/dist/tests/batch.test.js +0 -117
- package/dist/tests/body-parser.test.d.ts +0 -1
- package/dist/tests/body-parser.test.js +0 -52
- package/dist/tests/compression-sse.test.d.ts +0 -1
- package/dist/tests/compression-sse.test.js +0 -87
- package/dist/tests/cookies.test.d.ts +0 -1
- package/dist/tests/cookies.test.js +0 -63
- package/dist/tests/cors.test.d.ts +0 -1
- package/dist/tests/cors.test.js +0 -55
- package/dist/tests/database.test.d.ts +0 -1
- package/dist/tests/database.test.js +0 -80
- package/dist/tests/dx.test.d.ts +0 -1
- package/dist/tests/dx.test.js +0 -114
- package/dist/tests/ecosystem.test.d.ts +0 -1
- package/dist/tests/ecosystem.test.js +0 -133
- package/dist/tests/features.test.d.ts +0 -1
- package/dist/tests/features.test.js +0 -47
- package/dist/tests/fusion.test.d.ts +0 -1
- package/dist/tests/fusion.test.js +0 -92
- package/dist/tests/http-basic.test.d.ts +0 -1
- package/dist/tests/http-basic.test.js +0 -124
- package/dist/tests/logger.test.d.ts +0 -1
- package/dist/tests/logger.test.js +0 -33
- package/dist/tests/middleware.test.d.ts +0 -1
- package/dist/tests/middleware.test.js +0 -109
- package/dist/tests/native-adapter.test.d.ts +0 -1
- package/dist/tests/native-adapter.test.js +0 -71
- package/dist/tests/observability.test.d.ts +0 -1
- package/dist/tests/observability.test.js +0 -59
- package/dist/tests/openapi.test.d.ts +0 -1
- package/dist/tests/openapi.test.js +0 -64
- package/dist/tests/plugin.test.d.ts +0 -1
- package/dist/tests/plugin.test.js +0 -65
- package/dist/tests/plugins.test.d.ts +0 -1
- package/dist/tests/plugins.test.js +0 -71
- package/dist/tests/rate-limit.test.d.ts +0 -1
- package/dist/tests/rate-limit.test.js +0 -77
- package/dist/tests/resources.test.d.ts +0 -1
- package/dist/tests/resources.test.js +0 -47
- package/dist/tests/scheduler.test.d.ts +0 -1
- package/dist/tests/scheduler.test.js +0 -46
- package/dist/tests/schema-routes.test.d.ts +0 -1
- package/dist/tests/schema-routes.test.js +0 -77
- package/dist/tests/security.test.d.ts +0 -1
- package/dist/tests/security.test.js +0 -83
- package/dist/tests/server-db.test.d.ts +0 -1
- package/dist/tests/server-db.test.js +0 -72
- package/dist/tests/smoke.test.d.ts +0 -1
- package/dist/tests/smoke.test.js +0 -10
- package/dist/tests/sqlite-fusion.test.d.ts +0 -1
- package/dist/tests/sqlite-fusion.test.js +0 -92
- package/dist/tests/static.test.d.ts +0 -1
- package/dist/tests/static.test.js +0 -102
- package/dist/tests/stream.test.d.ts +0 -1
- package/dist/tests/stream.test.js +0 -44
- package/dist/tests/task-metrics.test.d.ts +0 -1
- package/dist/tests/task-metrics.test.js +0 -53
- package/dist/tests/tasks.test.d.ts +0 -1
- package/dist/tests/tasks.test.js +0 -62
- package/dist/tests/testing.test.d.ts +0 -1
- package/dist/tests/testing.test.js +0 -47
- package/dist/tests/validation.test.d.ts +0 -1
- package/dist/tests/validation.test.js +0 -107
- package/dist/tests/websocket.test.d.ts +0 -1
- package/dist/tests/websocket.test.js +0 -146
- package/dist/vitest.config.d.ts +0 -2
- package/dist/vitest.config.js +0 -9
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qhttpx",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "The
|
|
3
|
+
"version": "1.9.0",
|
|
4
|
+
"description": "The Ultra-Fast HTTP Framework for Node.js",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
19
|
"src/native",
|
|
20
|
+
"prebuilds",
|
|
21
|
+
"scripts",
|
|
20
22
|
"binding.gyp",
|
|
21
23
|
"README.md",
|
|
22
24
|
"LICENSE",
|
|
@@ -27,6 +29,7 @@
|
|
|
27
29
|
"doc": "docs"
|
|
28
30
|
},
|
|
29
31
|
"scripts": {
|
|
32
|
+
"prebuild": "prebuildify --napi --strip",
|
|
30
33
|
"build": "tsc -p tsconfig.json",
|
|
31
34
|
"lint": "eslint src tests --ext .ts",
|
|
32
35
|
"test": "vitest run",
|
|
@@ -63,6 +66,10 @@
|
|
|
63
66
|
],
|
|
64
67
|
"author": "Quantam Open Source",
|
|
65
68
|
"license": "MIT",
|
|
69
|
+
"repository": {
|
|
70
|
+
"type": "git",
|
|
71
|
+
"url": "https://github.com/Quantam-Open-Source/qhttpx"
|
|
72
|
+
},
|
|
66
73
|
"type": "commonjs",
|
|
67
74
|
"devDependencies": {
|
|
68
75
|
"@types/autocannon": "^7.12.7",
|
|
@@ -81,7 +88,9 @@
|
|
|
81
88
|
"eslint-config-prettier": "^10.1.8",
|
|
82
89
|
"eslint-plugin-prettier": "^5.5.5",
|
|
83
90
|
"mongodb": "^7.0.0",
|
|
91
|
+
"node-addon-api": "^8.5.0",
|
|
84
92
|
"pg": "^8.17.1",
|
|
93
|
+
"prebuildify": "^6.0.1",
|
|
85
94
|
"prettier": "^3.8.0",
|
|
86
95
|
"tsx": "^4.21.0",
|
|
87
96
|
"typescript": "^5.9.3",
|
|
@@ -91,7 +100,7 @@
|
|
|
91
100
|
"better-sqlite3": "^12.6.2",
|
|
92
101
|
"busboy": "^1.6.0",
|
|
93
102
|
"fast-json-stringify": "^5.15.1",
|
|
94
|
-
"node-
|
|
103
|
+
"node-gyp-build": "^4.8.4",
|
|
95
104
|
"pino": "^10.2.0",
|
|
96
105
|
"pino-pretty": "^13.1.3",
|
|
97
106
|
"quantam-async": "^0.1.1",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/native/index.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
3
|
+
const loadBinding = require('node-gyp-build');
|
|
1
4
|
|
|
5
|
+
// EXPECTED ABI VERSION
|
|
6
|
+
const EXPECTED_ABI = 1;
|
|
2
7
|
|
|
3
8
|
export interface NativeServerBinding {
|
|
4
9
|
parse(buffer: Buffer): {
|
|
@@ -17,23 +22,24 @@ export interface NativeServerBinding {
|
|
|
17
22
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
23
|
let nativeBinding: any = null;
|
|
19
24
|
|
|
20
|
-
// Use try/catch with module.createRequire if import.meta is not available in some build targets
|
|
21
|
-
// However, since we are in a TS module that might be commonjs or esm
|
|
22
|
-
// We'll use a safer approach for require
|
|
23
25
|
try {
|
|
24
|
-
|
|
26
|
+
// Look for prebuilds or built binary in root
|
|
27
|
+
const rootDir = __dirname.includes('dist')
|
|
28
|
+
? path.join(__dirname, '..', '..', '..')
|
|
29
|
+
: path.join(__dirname, '..', '..');
|
|
30
|
+
|
|
31
|
+
const binding = loadBinding(rootDir);
|
|
25
32
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
33
|
+
// 5. Version lock the ABI
|
|
34
|
+
if (binding && binding.abi === EXPECTED_ABI) {
|
|
35
|
+
nativeBinding = binding;
|
|
36
|
+
} else if (binding) {
|
|
37
|
+
// Version mismatch - disable native
|
|
38
|
+
// console.warn(`QHTTPX: Native ABI mismatch (Expected: ${EXPECTED_ABI}, Got: ${binding.abi}). Falling back to JS.`);
|
|
39
|
+
nativeBinding = null;
|
|
34
40
|
}
|
|
35
41
|
} catch {
|
|
36
|
-
//
|
|
42
|
+
// Graceful fallback to JS implementation
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
export class NativeServer {
|
|
@@ -41,7 +47,11 @@ export class NativeServer {
|
|
|
41
47
|
|
|
42
48
|
constructor() {
|
|
43
49
|
if (nativeBinding && nativeBinding.NativeServer) {
|
|
44
|
-
|
|
50
|
+
try {
|
|
51
|
+
this.binding = new nativeBinding.NativeServer();
|
|
52
|
+
} catch {
|
|
53
|
+
this.binding = null;
|
|
54
|
+
}
|
|
45
55
|
} else {
|
|
46
56
|
this.binding = null;
|
|
47
57
|
}
|
|
@@ -51,28 +61,98 @@ export class NativeServer {
|
|
|
51
61
|
return this.binding !== null;
|
|
52
62
|
}
|
|
53
63
|
|
|
64
|
+
// 4. Guard every native call
|
|
54
65
|
public parse(buffer: Buffer) {
|
|
55
|
-
if (
|
|
56
|
-
|
|
66
|
+
if (this.binding) {
|
|
67
|
+
try {
|
|
68
|
+
return this.binding.parse(buffer);
|
|
69
|
+
} catch {
|
|
70
|
+
this.disableNative();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Fallback: If native parse fails, we return null.
|
|
74
|
+
// The NativeAdapter will see null and might close the connection or handle error.
|
|
75
|
+
// We cannot easily implement a full HTTP parser in JS here without adding dependencies.
|
|
76
|
+
// But since NativeAdapter falls back to http.Server if !isAvailable,
|
|
77
|
+
// disabling native here ensures subsequent requests use the safe path.
|
|
78
|
+
return null;
|
|
57
79
|
}
|
|
58
80
|
|
|
59
81
|
public createResponse(statusCode: number, headers: Record<string, string>, body?: string | Buffer) {
|
|
60
|
-
if (
|
|
61
|
-
|
|
82
|
+
if (this.binding) {
|
|
83
|
+
try {
|
|
84
|
+
return this.binding.createResponse(statusCode, headers, body);
|
|
85
|
+
} catch {
|
|
86
|
+
this.disableNative();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return this.jsCreateResponse(statusCode, headers, body);
|
|
62
90
|
}
|
|
63
91
|
|
|
64
92
|
public createJSONResponse(obj: unknown) {
|
|
65
|
-
if (
|
|
66
|
-
|
|
93
|
+
if (this.binding) {
|
|
94
|
+
try {
|
|
95
|
+
return this.binding.createJSONResponse(obj);
|
|
96
|
+
} catch {
|
|
97
|
+
this.disableNative();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Fallback: Use JSON.stringify + Buffer
|
|
101
|
+
return this.jsCreateJSONResponse(obj);
|
|
67
102
|
}
|
|
68
103
|
|
|
69
104
|
public writeResponse(fd: number, chunks: (Buffer | string)[]) {
|
|
70
|
-
if (
|
|
71
|
-
|
|
105
|
+
if (this.binding) {
|
|
106
|
+
try {
|
|
107
|
+
return this.binding.writeResponse(fd, chunks);
|
|
108
|
+
} catch {
|
|
109
|
+
this.disableNative();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// No JS fallback for raw FD writes (requires net.Socket usually)
|
|
113
|
+
// The caller (NativeAdapter) should handle this by using socket.write()
|
|
114
|
+
// We throw here so caller knows to use fallback
|
|
115
|
+
throw new Error('Native writeResponse not available');
|
|
72
116
|
}
|
|
73
117
|
|
|
74
118
|
public setCPUAffinity(cpuId: number) {
|
|
75
|
-
if (
|
|
76
|
-
|
|
119
|
+
if (this.binding) {
|
|
120
|
+
try {
|
|
121
|
+
return this.binding.setCPUAffinity(cpuId);
|
|
122
|
+
} catch {
|
|
123
|
+
this.disableNative();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private disableNative() {
|
|
130
|
+
this.binding = null;
|
|
131
|
+
// console.warn('QHTTPX: Native module disabled due to error. Falling back to JS.');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// --- JS Fallbacks ---
|
|
135
|
+
|
|
136
|
+
private jsCreateResponse(statusCode: number, headers: Record<string, string>, body?: string | Buffer): Buffer {
|
|
137
|
+
const statusMessage = statusCode === 200 ? 'OK' : 'Unknown'; // Simplified
|
|
138
|
+
let head = `HTTP/1.1 ${statusCode} ${statusMessage}\r\n`;
|
|
139
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
140
|
+
head += `${key}: ${value}\r\n`;
|
|
141
|
+
}
|
|
142
|
+
head += '\r\n';
|
|
143
|
+
|
|
144
|
+
const headBuf = Buffer.from(head);
|
|
145
|
+
if (body) {
|
|
146
|
+
const bodyBuf = Buffer.isBuffer(body) ? body : Buffer.from(body);
|
|
147
|
+
return Buffer.concat([headBuf, bodyBuf]);
|
|
148
|
+
}
|
|
149
|
+
return headBuf;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private jsCreateJSONResponse(obj: unknown): Buffer {
|
|
153
|
+
const json = JSON.stringify(obj);
|
|
154
|
+
const contentLen = Buffer.byteLength(json);
|
|
155
|
+
const head = `HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: ${contentLen}\r\n\r\n`;
|
|
156
|
+
return Buffer.concat([Buffer.from(head), Buffer.from(json)]);
|
|
77
157
|
}
|
|
78
158
|
}
|
package/src/native/server.cc
CHANGED
|
@@ -26,6 +26,8 @@ Napi::Object NativeServer::Init(Napi::Env env, Napi::Object exports) {
|
|
|
26
26
|
env.SetInstanceData(constructor);
|
|
27
27
|
|
|
28
28
|
exports.Set("NativeServer", func);
|
|
29
|
+
// Version Lock: Expose ABI version
|
|
30
|
+
exports.Set("abi", Napi::Number::New(env, 1));
|
|
29
31
|
return exports;
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const index_1 = require("../src/index");
|
|
4
|
-
const dotenv_1 = require("dotenv");
|
|
5
|
-
// Load .env
|
|
6
|
-
(0, dotenv_1.config)();
|
|
7
|
-
// 1. Initialize App (Fusion + Aegis enabled)
|
|
8
|
-
const app = (0, index_1.createHttpApp)({
|
|
9
|
-
enableRequestFusion: true, // ⚡ Auto-coalesce duplicate requests
|
|
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)
|
|
18
|
-
});
|
|
19
|
-
// 2. Global Middleware (Logging is built-in by default)
|
|
20
|
-
// No manual app.use(rateLimit(...)) needed!
|
|
21
|
-
// 3. Validation Schema
|
|
22
|
-
const UserSchema = {
|
|
23
|
-
body: {
|
|
24
|
-
type: 'object',
|
|
25
|
-
required: ['name', 'role'],
|
|
26
|
-
properties: { name: { type: 'string' }, role: { type: 'string' } }
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
// 4. Routes (Clean & Destructured)
|
|
30
|
-
app.get('/', ({ json }) => json({ status: 'online', fusion: true }));
|
|
31
|
-
// ⚡ Fused Endpoint: 1000 concurrent requests -> 1 DB execution
|
|
32
|
-
app.get('/heavy', async ({ json }) => {
|
|
33
|
-
await new Promise(r => setTimeout(r, 100)); // Simulate DB
|
|
34
|
-
json({ data: 'Expensive Result', timestamp: Date.now() });
|
|
35
|
-
});
|
|
36
|
-
// 🛡️ Validated & Typed Route
|
|
37
|
-
app.post('/users', { schema: UserSchema }, async ({ body, json }) => {
|
|
38
|
-
// Body is already validated and typed here
|
|
39
|
-
json({ created: true, user: body }, 201);
|
|
40
|
-
});
|
|
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)
|
|
50
|
-
app.post('/upload', ({ files, json }) => {
|
|
51
|
-
if (!files?.doc)
|
|
52
|
-
return json({ error: 'No file' }, 400);
|
|
53
|
-
const doc = Array.isArray(files.doc) ? files.doc[0] : files.doc;
|
|
54
|
-
json({ filename: doc.filename, size: doc.size });
|
|
55
|
-
});
|
|
56
|
-
// 📡 WebSockets (Pub/Sub)
|
|
57
|
-
app.upgrade('/chat', (ws) => {
|
|
58
|
-
ws.join('general'); // Auto-join room
|
|
59
|
-
ws.on('message', (msg) => {
|
|
60
|
-
// Broadcast to room
|
|
61
|
-
app.websocket.to('general').emit(`Echo: ${msg}`);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
// 5. Unified Error Handling
|
|
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
|
-
}
|
|
73
|
-
console.error(error); // Log internal error
|
|
74
|
-
json({ error: 'Internal Server Error', handled: true }, 500);
|
|
75
|
-
});
|
|
76
|
-
// 6. Start Server
|
|
77
|
-
app.listen(3000, () => console.log('🚀 Server running on http://localhost:3000'));
|
package/dist/examples/basic.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/examples/basic.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,17 +0,0 @@
|
|
|
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
|
-
});
|
package/dist/examples/cors.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/examples/cors.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/examples/errors.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,24 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/examples/fusion.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,17 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,23 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,20 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "qhttpx",
|
|
3
|
-
"version": "1.8.12",
|
|
4
|
-
"description": "The High-Performance Hybrid HTTP Runtime for Node.js. Built for extreme concurrency, request fusion, and zero-overhead scaling.",
|
|
5
|
-
"main": "dist/src/index.js",
|
|
6
|
-
"types": "dist/src/index.d.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": {
|
|
9
|
-
"types": "./dist/src/index.d.ts",
|
|
10
|
-
"require": "./dist/src/index.js",
|
|
11
|
-
"default": "./dist/src/index.js"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"bin": {
|
|
15
|
-
"qhttpx": "./dist/src/cli/index.js"
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"dist",
|
|
19
|
-
"src/native",
|
|
20
|
-
"binding.gyp",
|
|
21
|
-
"README.md",
|
|
22
|
-
"LICENSE",
|
|
23
|
-
"CHANGELOG.md",
|
|
24
|
-
"docs"
|
|
25
|
-
],
|
|
26
|
-
"directories": {
|
|
27
|
-
"doc": "docs"
|
|
28
|
-
},
|
|
29
|
-
"scripts": {
|
|
30
|
-
"build": "tsc -p tsconfig.json",
|
|
31
|
-
"lint": "eslint src tests --ext .ts",
|
|
32
|
-
"test": "vitest run",
|
|
33
|
-
"example": "npx tsx examples/api-server.ts",
|
|
34
|
-
"bench": "npm run build && node dist/src/benchmarks/simple-json.js",
|
|
35
|
-
"bench:quantam": "npm run build && node dist/src/benchmarks/quantam-users.js",
|
|
36
|
-
"bench:ultra": "npm run build && node dist/src/benchmarks/ultra-mode.js"
|
|
37
|
-
},
|
|
38
|
-
"keywords": [
|
|
39
|
-
"http",
|
|
40
|
-
"server",
|
|
41
|
-
"web",
|
|
42
|
-
"framework",
|
|
43
|
-
"typescript",
|
|
44
|
-
"fast",
|
|
45
|
-
"performance",
|
|
46
|
-
"high-performance",
|
|
47
|
-
"async",
|
|
48
|
-
"concurrency",
|
|
49
|
-
"request-fusion",
|
|
50
|
-
"coalescing",
|
|
51
|
-
"middleware",
|
|
52
|
-
"websocket",
|
|
53
|
-
"sse",
|
|
54
|
-
"rate-limit",
|
|
55
|
-
"rest",
|
|
56
|
-
"api",
|
|
57
|
-
"json",
|
|
58
|
-
"router",
|
|
59
|
-
"radix-tree",
|
|
60
|
-
"scheduler",
|
|
61
|
-
"ultra-fast",
|
|
62
|
-
"nodejs"
|
|
63
|
-
],
|
|
64
|
-
"author": "Quantam Open Source",
|
|
65
|
-
"license": "MIT",
|
|
66
|
-
"type": "commonjs",
|
|
67
|
-
"devDependencies": {
|
|
68
|
-
"@types/autocannon": "^7.12.7",
|
|
69
|
-
"@types/better-sqlite3": "^7.6.13",
|
|
70
|
-
"@types/busboy": "^1.5.4",
|
|
71
|
-
"@types/ioredis": "^4.28.10",
|
|
72
|
-
"@types/mongodb": "^4.0.6",
|
|
73
|
-
"@types/node": "^25.0.9",
|
|
74
|
-
"@types/pg": "^8.16.0",
|
|
75
|
-
"@types/ws": "^8.18.1",
|
|
76
|
-
"@typescript-eslint/eslint-plugin": "^8.53.0",
|
|
77
|
-
"@typescript-eslint/parser": "^8.53.0",
|
|
78
|
-
"autocannon": "^8.0.0",
|
|
79
|
-
"dotenv": "^17.2.3",
|
|
80
|
-
"eslint": "^9.39.2",
|
|
81
|
-
"eslint-config-prettier": "^10.1.8",
|
|
82
|
-
"eslint-plugin-prettier": "^5.5.5",
|
|
83
|
-
"mongodb": "^7.0.0",
|
|
84
|
-
"pg": "^8.17.1",
|
|
85
|
-
"prettier": "^3.8.0",
|
|
86
|
-
"tsx": "^4.21.0",
|
|
87
|
-
"typescript": "^5.9.3",
|
|
88
|
-
"vitest": "^4.0.17"
|
|
89
|
-
},
|
|
90
|
-
"dependencies": {
|
|
91
|
-
"better-sqlite3": "^12.6.2",
|
|
92
|
-
"busboy": "^1.6.0",
|
|
93
|
-
"fast-json-stringify": "^5.15.1",
|
|
94
|
-
"node-addon-api": "^8.5.0",
|
|
95
|
-
"pino": "^10.2.0",
|
|
96
|
-
"pino-pretty": "^13.1.3",
|
|
97
|
-
"quantam-async": "^0.1.1",
|
|
98
|
-
"ws": "^8.19.0",
|
|
99
|
-
"zod": "^4.3.5"
|
|
100
|
-
}
|
|
101
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|