qhttpx 1.8.11 → 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
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { TaskEngine, TaskMetrics } from './tasks';
|
|
2
|
-
import { Scheduler } from './scheduler';
|
|
3
|
-
export type LatencySnapshot = {
|
|
4
|
-
p50: number | null;
|
|
5
|
-
p95: number | null;
|
|
6
|
-
p99: number | null;
|
|
7
|
-
};
|
|
8
|
-
export type MetricsSnapshot = {
|
|
9
|
-
totalRequests: number;
|
|
10
|
-
inFlightRequests: number;
|
|
11
|
-
totalErrors: number;
|
|
12
|
-
totalTimeouts: number;
|
|
13
|
-
requestsPerSecond: number;
|
|
14
|
-
latency: LatencySnapshot;
|
|
15
|
-
scheduler: {
|
|
16
|
-
inFlight: number;
|
|
17
|
-
};
|
|
18
|
-
tasks?: TaskMetrics;
|
|
19
|
-
memory: {
|
|
20
|
-
rssBytes: number;
|
|
21
|
-
heapUsedBytes: number;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
export declare class Metrics {
|
|
25
|
-
private readonly scheduler;
|
|
26
|
-
private readonly taskEngine?;
|
|
27
|
-
private readonly latencies;
|
|
28
|
-
private readonly maxLatencies;
|
|
29
|
-
private readonly enabled;
|
|
30
|
-
private totalRequests;
|
|
31
|
-
private inFlightRequests;
|
|
32
|
-
private totalErrors;
|
|
33
|
-
private totalTimeouts;
|
|
34
|
-
constructor(scheduler: Scheduler, options?: {
|
|
35
|
-
maxLatencies?: number;
|
|
36
|
-
enabled?: boolean;
|
|
37
|
-
}, taskEngine?: TaskEngine);
|
|
38
|
-
onRequestStart(): void;
|
|
39
|
-
onRequestEnd(durationMs: number, statusCode: number): void;
|
|
40
|
-
onTimeout(): void;
|
|
41
|
-
snapshot(): MetricsSnapshot;
|
|
42
|
-
private recordLatency;
|
|
43
|
-
private latencySnapshot;
|
|
44
|
-
private percentile;
|
|
45
|
-
}
|
package/dist/src/core/metrics.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Metrics = void 0;
|
|
4
|
-
class Metrics {
|
|
5
|
-
constructor(scheduler, options = {}, taskEngine) {
|
|
6
|
-
this.latencies = [];
|
|
7
|
-
this.totalRequests = 0;
|
|
8
|
-
this.inFlightRequests = 0;
|
|
9
|
-
this.totalErrors = 0;
|
|
10
|
-
this.totalTimeouts = 0;
|
|
11
|
-
this.scheduler = scheduler;
|
|
12
|
-
this.taskEngine = taskEngine;
|
|
13
|
-
this.maxLatencies = options.maxLatencies ?? 1000;
|
|
14
|
-
this.enabled = options.enabled ?? true;
|
|
15
|
-
}
|
|
16
|
-
onRequestStart() {
|
|
17
|
-
if (!this.enabled) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
this.inFlightRequests += 1;
|
|
21
|
-
}
|
|
22
|
-
onRequestEnd(durationMs, statusCode) {
|
|
23
|
-
if (!this.enabled) {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
this.totalRequests += 1;
|
|
27
|
-
if (this.inFlightRequests > 0) {
|
|
28
|
-
this.inFlightRequests -= 1;
|
|
29
|
-
}
|
|
30
|
-
if (statusCode >= 500) {
|
|
31
|
-
this.totalErrors += 1;
|
|
32
|
-
}
|
|
33
|
-
this.recordLatency(durationMs);
|
|
34
|
-
}
|
|
35
|
-
onTimeout() {
|
|
36
|
-
if (!this.enabled) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
this.totalTimeouts += 1;
|
|
40
|
-
}
|
|
41
|
-
snapshot() {
|
|
42
|
-
const uptime = process.uptime();
|
|
43
|
-
const requestsPerSecond = uptime > 0 ? this.totalRequests / uptime : this.totalRequests;
|
|
44
|
-
const latency = this.latencySnapshot();
|
|
45
|
-
const memoryUsage = process.memoryUsage();
|
|
46
|
-
let tasks;
|
|
47
|
-
if (this.taskEngine) {
|
|
48
|
-
tasks = this.taskEngine.getMetrics();
|
|
49
|
-
}
|
|
50
|
-
return {
|
|
51
|
-
totalRequests: this.totalRequests,
|
|
52
|
-
inFlightRequests: this.inFlightRequests,
|
|
53
|
-
totalErrors: this.totalErrors,
|
|
54
|
-
totalTimeouts: this.totalTimeouts,
|
|
55
|
-
requestsPerSecond,
|
|
56
|
-
latency,
|
|
57
|
-
scheduler: {
|
|
58
|
-
inFlight: this.scheduler.getCurrentInFlight(),
|
|
59
|
-
},
|
|
60
|
-
tasks,
|
|
61
|
-
memory: {
|
|
62
|
-
rssBytes: memoryUsage.rss,
|
|
63
|
-
heapUsedBytes: memoryUsage.heapUsed,
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
recordLatency(durationMs) {
|
|
68
|
-
if (!this.enabled) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
if (!Number.isFinite(durationMs) || durationMs < 0) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
this.latencies.push(durationMs);
|
|
75
|
-
if (this.latencies.length > this.maxLatencies) {
|
|
76
|
-
this.latencies.shift();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
latencySnapshot() {
|
|
80
|
-
if (this.latencies.length === 0) {
|
|
81
|
-
return {
|
|
82
|
-
p50: null,
|
|
83
|
-
p95: null,
|
|
84
|
-
p99: null,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
const sorted = [...this.latencies].sort((a, b) => a - b);
|
|
88
|
-
const p50 = this.percentile(sorted, 0.5);
|
|
89
|
-
const p95 = this.percentile(sorted, 0.95);
|
|
90
|
-
const p99 = this.percentile(sorted, 0.99);
|
|
91
|
-
return {
|
|
92
|
-
p50,
|
|
93
|
-
p95,
|
|
94
|
-
p99,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
percentile(sorted, p) {
|
|
98
|
-
if (sorted.length === 0) {
|
|
99
|
-
return 0;
|
|
100
|
-
}
|
|
101
|
-
if (p <= 0) {
|
|
102
|
-
return sorted[0];
|
|
103
|
-
}
|
|
104
|
-
if (p >= 1) {
|
|
105
|
-
return sorted[sorted.length - 1];
|
|
106
|
-
}
|
|
107
|
-
const index = Math.floor(p * (sorted.length - 1));
|
|
108
|
-
return sorted[index];
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
exports.Metrics = Metrics;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import net from 'net';
|
|
2
|
-
import { QHTTPX } from './server';
|
|
3
|
-
export declare class NativeAdapter {
|
|
4
|
-
private app;
|
|
5
|
-
private nativeServer;
|
|
6
|
-
private responsePool;
|
|
7
|
-
constructor(app: QHTTPX);
|
|
8
|
-
listen(port: number, cb?: () => void): net.Server | Promise<{
|
|
9
|
-
port: number;
|
|
10
|
-
}>;
|
|
11
|
-
}
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.NativeAdapter = void 0;
|
|
7
|
-
const net_1 = __importDefault(require("net"));
|
|
8
|
-
const stream_1 = require("stream");
|
|
9
|
-
const native_1 = require("../native");
|
|
10
|
-
class MockIncomingMessage extends stream_1.Readable {
|
|
11
|
-
constructor(socket, method, url, headers) {
|
|
12
|
-
super();
|
|
13
|
-
this.httpVersion = '1.1';
|
|
14
|
-
this.socket = socket;
|
|
15
|
-
this.method = method;
|
|
16
|
-
this.url = url;
|
|
17
|
-
this.headers = headers;
|
|
18
|
-
}
|
|
19
|
-
_read() {
|
|
20
|
-
// No-op, data is pushed manually
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
class MockServerResponse extends stream_1.Writable {
|
|
24
|
-
constructor(socket, nativeServer) {
|
|
25
|
-
super();
|
|
26
|
-
this.statusCode = 200;
|
|
27
|
-
this.headersSent = false;
|
|
28
|
-
this.headers = {};
|
|
29
|
-
this.socket = socket;
|
|
30
|
-
this.nativeServer = nativeServer;
|
|
31
|
-
}
|
|
32
|
-
setHeader(name, value) {
|
|
33
|
-
this.headers[name.toLowerCase()] = value;
|
|
34
|
-
return this;
|
|
35
|
-
}
|
|
36
|
-
getHeader(name) {
|
|
37
|
-
return this.headers[name.toLowerCase()];
|
|
38
|
-
}
|
|
39
|
-
getHeaders() {
|
|
40
|
-
return { ...this.headers };
|
|
41
|
-
}
|
|
42
|
-
hasHeader(name) {
|
|
43
|
-
return Object.prototype.hasOwnProperty.call(this.headers, name.toLowerCase());
|
|
44
|
-
}
|
|
45
|
-
removeHeader(name) {
|
|
46
|
-
delete this.headers[name.toLowerCase()];
|
|
47
|
-
}
|
|
48
|
-
writeHead(statusCode, headers) {
|
|
49
|
-
this.statusCode = statusCode;
|
|
50
|
-
if (headers) {
|
|
51
|
-
for (const key in headers) {
|
|
52
|
-
this.setHeader(key, headers[key]);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return this;
|
|
56
|
-
}
|
|
57
|
-
reset(socket) {
|
|
58
|
-
this.socket = socket;
|
|
59
|
-
this.statusCode = 200;
|
|
60
|
-
this.headersSent = false;
|
|
61
|
-
this.headers = {};
|
|
62
|
-
this.removeAllListeners();
|
|
63
|
-
}
|
|
64
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
-
_write(chunk, encoding, callback) {
|
|
66
|
-
if (!this.headersSent) {
|
|
67
|
-
this.sendHeaders();
|
|
68
|
-
}
|
|
69
|
-
this.socket.write(chunk, encoding, callback);
|
|
70
|
-
}
|
|
71
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
|
-
end(arg1, arg2, arg3) {
|
|
73
|
-
if (arg1 && typeof arg1 !== 'function') {
|
|
74
|
-
if (!this.headersSent) {
|
|
75
|
-
// Optimization: Use native createResponse / createJSONResponse if possible
|
|
76
|
-
try {
|
|
77
|
-
let respBuffer;
|
|
78
|
-
// Check for JSON object (not buffer/string)
|
|
79
|
-
if (typeof arg1 === 'object' && !Buffer.isBuffer(arg1)) {
|
|
80
|
-
respBuffer = this.nativeServer.createJSONResponse(arg1);
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
const body = arg1;
|
|
84
|
-
const headers = {};
|
|
85
|
-
for (const k in this.headers) {
|
|
86
|
-
const v = this.headers[k];
|
|
87
|
-
headers[k] = Array.isArray(v) ? v.join(', ') : String(v);
|
|
88
|
-
}
|
|
89
|
-
respBuffer = this.nativeServer.createResponse(this.statusCode, headers, body);
|
|
90
|
-
}
|
|
91
|
-
// Try direct writeResponse if FD is available
|
|
92
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
|
-
const fd = this.socket._handle?.fd;
|
|
94
|
-
if (typeof fd === 'number' && fd >= 0) {
|
|
95
|
-
this.nativeServer.writeResponse(fd, [respBuffer]);
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
this.socket.write(respBuffer);
|
|
99
|
-
}
|
|
100
|
-
this.headersSent = true;
|
|
101
|
-
if (arg2 && typeof arg2 === 'function')
|
|
102
|
-
arg2();
|
|
103
|
-
else if (arg3 && typeof arg3 === 'function')
|
|
104
|
-
arg3();
|
|
105
|
-
return this;
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
// Fallback
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
this.write(arg1, arg2);
|
|
112
|
-
}
|
|
113
|
-
if (!this.headersSent) {
|
|
114
|
-
this.sendHeaders();
|
|
115
|
-
}
|
|
116
|
-
super.end();
|
|
117
|
-
if (arg1 && typeof arg1 === 'function')
|
|
118
|
-
arg1();
|
|
119
|
-
else if (arg2 && typeof arg2 === 'function')
|
|
120
|
-
arg2();
|
|
121
|
-
else if (arg3 && typeof arg3 === 'function')
|
|
122
|
-
arg3();
|
|
123
|
-
return this;
|
|
124
|
-
}
|
|
125
|
-
sendHeaders() {
|
|
126
|
-
let head = `HTTP/1.1 ${this.statusCode} OK\r\n`; // Status msg todo
|
|
127
|
-
for (const key in this.headers) {
|
|
128
|
-
const val = this.headers[key];
|
|
129
|
-
if (Array.isArray(val)) {
|
|
130
|
-
for (const v of val) {
|
|
131
|
-
head += `${key}: ${v}\r\n`;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
head += `${key}: ${val}\r\n`;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
head += '\r\n';
|
|
139
|
-
this.socket.write(head);
|
|
140
|
-
this.headersSent = true;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
class MockResponsePool {
|
|
144
|
-
constructor(nativeServer) {
|
|
145
|
-
this.pool = [];
|
|
146
|
-
this.nativeServer = nativeServer;
|
|
147
|
-
}
|
|
148
|
-
acquire(socket) {
|
|
149
|
-
const res = this.pool.pop();
|
|
150
|
-
if (res) {
|
|
151
|
-
res.reset(socket);
|
|
152
|
-
return res;
|
|
153
|
-
}
|
|
154
|
-
return new MockServerResponse(socket, this.nativeServer);
|
|
155
|
-
}
|
|
156
|
-
release(res) {
|
|
157
|
-
// Simple cap to prevent memory leak if something goes wrong
|
|
158
|
-
if (this.pool.length < 2000) {
|
|
159
|
-
this.pool.push(res);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
class NativeAdapter {
|
|
164
|
-
constructor(app) {
|
|
165
|
-
this.app = app;
|
|
166
|
-
this.nativeServer = new native_1.NativeServer();
|
|
167
|
-
this.responsePool = new MockResponsePool(this.nativeServer);
|
|
168
|
-
}
|
|
169
|
-
listen(port, cb) {
|
|
170
|
-
if (!this.nativeServer.isAvailable) {
|
|
171
|
-
console.warn('Native server not available, falling back to Node.js HTTP');
|
|
172
|
-
return this.app.listen(port, cb);
|
|
173
|
-
}
|
|
174
|
-
const server = net_1.default.createServer((socket) => {
|
|
175
|
-
let buffer = Buffer.alloc(0);
|
|
176
|
-
socket.on('data', (chunk) => {
|
|
177
|
-
buffer = buffer.length === 0 ? chunk : Buffer.concat([buffer, chunk]);
|
|
178
|
-
// Try parsing
|
|
179
|
-
const res = this.nativeServer.parse(buffer);
|
|
180
|
-
if (res) {
|
|
181
|
-
// Parsed successfully
|
|
182
|
-
const req = new MockIncomingMessage(socket, res.method, res.path, res.headers);
|
|
183
|
-
const response = this.responsePool.acquire(socket);
|
|
184
|
-
response.on('finish', () => {
|
|
185
|
-
this.responsePool.release(response);
|
|
186
|
-
});
|
|
187
|
-
// Push body if any
|
|
188
|
-
if (res.bodyOffset < buffer.length) {
|
|
189
|
-
req.push(buffer.slice(res.bodyOffset));
|
|
190
|
-
}
|
|
191
|
-
req.push(null); // End of body (assuming single packet for now or content-length handling needed for real impl)
|
|
192
|
-
// Reset buffer for pipelining support (not implemented here, assuming connection: close or one req per packet for simplicity)
|
|
193
|
-
buffer = Buffer.alloc(0);
|
|
194
|
-
// Dispatch to QHTTPX
|
|
195
|
-
this.app.handleRequest(req, response);
|
|
196
|
-
}
|
|
197
|
-
else if (res === null) {
|
|
198
|
-
// Error
|
|
199
|
-
socket.destroy();
|
|
200
|
-
}
|
|
201
|
-
// else undefined -> partial, wait for more data
|
|
202
|
-
});
|
|
203
|
-
socket.on('error', () => {
|
|
204
|
-
// console.error(err);
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
server.listen(port, cb);
|
|
208
|
-
return server;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
exports.NativeAdapter = NativeAdapter;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export type WorkerSetting = 'auto' | number;
|
|
2
|
-
export declare function calculateWorkerCount(setting: WorkerSetting): number;
|
|
3
|
-
export type ResourceThresholds = {
|
|
4
|
-
maxRssBytes?: number;
|
|
5
|
-
};
|
|
6
|
-
export type ResourceSample = {
|
|
7
|
-
rssBytes: number;
|
|
8
|
-
};
|
|
9
|
-
export declare function isResourceOverloaded(sample: ResourceSample, thresholds: ResourceThresholds): boolean;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.calculateWorkerCount = calculateWorkerCount;
|
|
7
|
-
exports.isResourceOverloaded = isResourceOverloaded;
|
|
8
|
-
const os_1 = __importDefault(require("os"));
|
|
9
|
-
function calculateWorkerCount(setting) {
|
|
10
|
-
if (typeof setting === 'number') {
|
|
11
|
-
if (!Number.isFinite(setting) || setting <= 0) {
|
|
12
|
-
return 1;
|
|
13
|
-
}
|
|
14
|
-
return Math.floor(setting);
|
|
15
|
-
}
|
|
16
|
-
const cpuCount = os_1.default.cpus().length || 1;
|
|
17
|
-
return Math.max(1, cpuCount);
|
|
18
|
-
}
|
|
19
|
-
function isResourceOverloaded(sample, thresholds) {
|
|
20
|
-
if (thresholds.maxRssBytes !== undefined &&
|
|
21
|
-
sample.rssBytes > thresholds.maxRssBytes) {
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { RoutePriority } from './types';
|
|
2
|
-
export type SchedulerOptions = {
|
|
3
|
-
maxConcurrency?: number;
|
|
4
|
-
workers?: number;
|
|
5
|
-
};
|
|
6
|
-
export type RunOptions = {
|
|
7
|
-
priority?: RoutePriority;
|
|
8
|
-
onOverloaded?: () => void;
|
|
9
|
-
timeoutMs?: number;
|
|
10
|
-
onTimeout?: () => void;
|
|
11
|
-
};
|
|
12
|
-
export type SchedulerStats = {
|
|
13
|
-
inFlight: number;
|
|
14
|
-
maxConcurrency: number;
|
|
15
|
-
workers: number;
|
|
16
|
-
perWorkerStats: {
|
|
17
|
-
workerId: number;
|
|
18
|
-
queued: number;
|
|
19
|
-
}[];
|
|
20
|
-
};
|
|
21
|
-
export declare class Scheduler {
|
|
22
|
-
private inFlight;
|
|
23
|
-
private readonly maxConcurrency;
|
|
24
|
-
private readonly workerCount;
|
|
25
|
-
private readonly perWorkerQueues;
|
|
26
|
-
private nextWorkerIndex;
|
|
27
|
-
constructor(options?: SchedulerOptions);
|
|
28
|
-
getCurrentInFlight(): number;
|
|
29
|
-
/**
|
|
30
|
-
* Get scheduler statistics (queued tasks per worker, etc.)
|
|
31
|
-
*/
|
|
32
|
-
getStats(): SchedulerStats;
|
|
33
|
-
run(task: () => void | Promise<void>, options: RunOptions): Promise<void>;
|
|
34
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Scheduler = void 0;
|
|
4
|
-
const worker_queue_1 = require("./worker-queue");
|
|
5
|
-
const types_1 = require("./types");
|
|
6
|
-
class Scheduler {
|
|
7
|
-
constructor(options = {}) {
|
|
8
|
-
this.inFlight = 0;
|
|
9
|
-
this.nextWorkerIndex = 0;
|
|
10
|
-
const max = options.maxConcurrency ?? Infinity;
|
|
11
|
-
this.maxConcurrency = max > 0 ? max : Infinity;
|
|
12
|
-
// Initialize per-worker queues
|
|
13
|
-
this.workerCount = options.workers ?? 1;
|
|
14
|
-
this.perWorkerQueues = [];
|
|
15
|
-
for (let i = 0; i < this.workerCount; i += 1) {
|
|
16
|
-
this.perWorkerQueues.push(new worker_queue_1.WorkerQueue(1024));
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
getCurrentInFlight() {
|
|
20
|
-
return this.inFlight;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Get scheduler statistics (queued tasks per worker, etc.)
|
|
24
|
-
*/
|
|
25
|
-
getStats() {
|
|
26
|
-
return {
|
|
27
|
-
inFlight: this.inFlight,
|
|
28
|
-
maxConcurrency: this.maxConcurrency,
|
|
29
|
-
workers: this.workerCount,
|
|
30
|
-
perWorkerStats: this.perWorkerQueues.map((q, i) => ({
|
|
31
|
-
workerId: i,
|
|
32
|
-
queued: q.getSize(),
|
|
33
|
-
})),
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
async run(task, options) {
|
|
37
|
-
const priority = options.priority ?? types_1.RoutePriority.STANDARD;
|
|
38
|
-
let threshold = this.maxConcurrency;
|
|
39
|
-
if (priority === types_1.RoutePriority.BEST_EFFORT) {
|
|
40
|
-
// Shed best-effort requests if we are above 80% capacity
|
|
41
|
-
threshold = Math.max(1, Math.floor(this.maxConcurrency * 0.8));
|
|
42
|
-
}
|
|
43
|
-
else if (priority === types_1.RoutePriority.STANDARD) {
|
|
44
|
-
// Shed standard requests if we are above 95% capacity
|
|
45
|
-
threshold = Math.max(1, Math.floor(this.maxConcurrency * 0.95));
|
|
46
|
-
}
|
|
47
|
-
// CRITICAL allows up to 100%
|
|
48
|
-
if (this.inFlight >= threshold) {
|
|
49
|
-
if (options.onOverloaded) {
|
|
50
|
-
options.onOverloaded();
|
|
51
|
-
}
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
this.inFlight += 1;
|
|
55
|
-
let timeoutId;
|
|
56
|
-
try {
|
|
57
|
-
if (!options.timeoutMs || options.timeoutMs <= 0) {
|
|
58
|
-
const result = task();
|
|
59
|
-
if (result && typeof result.then === 'function') {
|
|
60
|
-
await result;
|
|
61
|
-
}
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
const taskPromise = Promise.resolve(task()).then(() => 'ok');
|
|
65
|
-
const timeoutPromise = new Promise((resolve) => {
|
|
66
|
-
timeoutId = setTimeout(() => {
|
|
67
|
-
resolve('timeout');
|
|
68
|
-
}, options.timeoutMs);
|
|
69
|
-
});
|
|
70
|
-
const result = await Promise.race([taskPromise, timeoutPromise]);
|
|
71
|
-
if (result === 'timeout') {
|
|
72
|
-
if (options.onTimeout) {
|
|
73
|
-
options.onTimeout();
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
finally {
|
|
78
|
-
if (timeoutId) {
|
|
79
|
-
clearTimeout(timeoutId);
|
|
80
|
-
}
|
|
81
|
-
this.inFlight -= 1;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
exports.Scheduler = Scheduler;
|
package/dist/src/core/scope.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { QHTTPX } from './server';
|
|
2
|
-
import { QHTTPXHandler, QHTTPXRouteOptions, QHTTPXMiddleware, QHTTPXPlugin, QHTTPXPluginOptions } from './types';
|
|
3
|
-
/**
|
|
4
|
-
* A Scope represents a prefixed or isolated context for plugins.
|
|
5
|
-
* It proxies methods to the main QHTTPX instance but handles prefixing.
|
|
6
|
-
*/
|
|
7
|
-
export declare class QHTTPXScope {
|
|
8
|
-
private readonly app;
|
|
9
|
-
private readonly prefix;
|
|
10
|
-
constructor(app: QHTTPX, prefix?: string);
|
|
11
|
-
/**
|
|
12
|
-
* Registers a sub-plugin within this scope.
|
|
13
|
-
* Prefixes are concatenated (e.g. /v1 + /users = /v1/users).
|
|
14
|
-
*/
|
|
15
|
-
register<Options extends QHTTPXPluginOptions>(plugin: QHTTPXPlugin<Options>, options?: Options): Promise<void>;
|
|
16
|
-
use(middleware: QHTTPXMiddleware): void;
|
|
17
|
-
get(path: string, handler: QHTTPXHandler | QHTTPXRouteOptions): void;
|
|
18
|
-
post(path: string, handler: QHTTPXHandler | QHTTPXRouteOptions): void;
|
|
19
|
-
put(path: string, handler: QHTTPXHandler | QHTTPXRouteOptions): void;
|
|
20
|
-
delete(path: string, handler: QHTTPXHandler | QHTTPXRouteOptions): void;
|
|
21
|
-
patch(path: string, handler: QHTTPXHandler | QHTTPXRouteOptions): void;
|
|
22
|
-
options(path: string, handler: QHTTPXHandler | QHTTPXRouteOptions): void;
|
|
23
|
-
head(path: string, handler: QHTTPXHandler | QHTTPXRouteOptions): void;
|
|
24
|
-
getApp(): QHTTPX;
|
|
25
|
-
private joinPaths;
|
|
26
|
-
}
|
package/dist/src/core/scope.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.QHTTPXScope = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* A Scope represents a prefixed or isolated context for plugins.
|
|
6
|
-
* It proxies methods to the main QHTTPX instance but handles prefixing.
|
|
7
|
-
*/
|
|
8
|
-
class QHTTPXScope {
|
|
9
|
-
constructor(app, prefix = '') {
|
|
10
|
-
this.app = app;
|
|
11
|
-
this.prefix = prefix;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Registers a sub-plugin within this scope.
|
|
15
|
-
* Prefixes are concatenated (e.g. /v1 + /users = /v1/users).
|
|
16
|
-
*/
|
|
17
|
-
async register(plugin, options) {
|
|
18
|
-
const newPrefix = this.joinPaths(this.prefix, options?.prefix || '');
|
|
19
|
-
const scope = new QHTTPXScope(this.app, newPrefix);
|
|
20
|
-
await plugin(scope, options);
|
|
21
|
-
}
|
|
22
|
-
use(middleware) {
|
|
23
|
-
// Middleware in scopes is currently global (TODO: Encapsulated middleware)
|
|
24
|
-
this.app.use(middleware);
|
|
25
|
-
}
|
|
26
|
-
get(path, handler) {
|
|
27
|
-
this.app._registerRoute('GET', this.joinPaths(this.prefix, path), handler);
|
|
28
|
-
}
|
|
29
|
-
post(path, handler) {
|
|
30
|
-
this.app._registerRoute('POST', this.joinPaths(this.prefix, path), handler);
|
|
31
|
-
}
|
|
32
|
-
put(path, handler) {
|
|
33
|
-
this.app._registerRoute('PUT', this.joinPaths(this.prefix, path), handler);
|
|
34
|
-
}
|
|
35
|
-
delete(path, handler) {
|
|
36
|
-
this.app._registerRoute('DELETE', this.joinPaths(this.prefix, path), handler);
|
|
37
|
-
}
|
|
38
|
-
patch(path, handler) {
|
|
39
|
-
this.app._registerRoute('PATCH', this.joinPaths(this.prefix, path), handler);
|
|
40
|
-
}
|
|
41
|
-
options(path, handler) {
|
|
42
|
-
this.app._registerRoute('OPTIONS', this.joinPaths(this.prefix, path), handler);
|
|
43
|
-
}
|
|
44
|
-
head(path, handler) {
|
|
45
|
-
this.app._registerRoute('HEAD', this.joinPaths(this.prefix, path), handler);
|
|
46
|
-
}
|
|
47
|
-
// Helper to access the main app if needed
|
|
48
|
-
getApp() {
|
|
49
|
-
return this.app;
|
|
50
|
-
}
|
|
51
|
-
joinPaths(head, tail) {
|
|
52
|
-
if (!head)
|
|
53
|
-
return tail;
|
|
54
|
-
if (!tail)
|
|
55
|
-
return head;
|
|
56
|
-
// Ensure clean slash joining
|
|
57
|
-
const headSlash = head.endsWith('/');
|
|
58
|
-
const tailSlash = tail.startsWith('/');
|
|
59
|
-
if (headSlash && tailSlash) {
|
|
60
|
-
return head + tail.slice(1);
|
|
61
|
-
}
|
|
62
|
-
if (!headSlash && !tailSlash) {
|
|
63
|
-
return head + '/' + tail;
|
|
64
|
-
}
|
|
65
|
-
return head + tail;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
exports.QHTTPXScope = QHTTPXScope;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fast JSON serializer using fast-json-stringify
|
|
3
|
-
* For best performance, use schema-based stringifiers per route
|
|
4
|
-
*/
|
|
5
|
-
export declare function fastJsonStringify(value: unknown, schema?: unknown): string;
|
|
6
|
-
/**
|
|
7
|
-
* Get a pre-compiled stringifier for a specific schema
|
|
8
|
-
* Use this in route handlers for maximum performance
|
|
9
|
-
*/
|
|
10
|
-
export declare function getStringifier(schema: unknown): (value: unknown) => string;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.fastJsonStringify = fastJsonStringify;
|
|
7
|
-
exports.getStringifier = getStringifier;
|
|
8
|
-
const fast_json_stringify_1 = __importDefault(require("fast-json-stringify"));
|
|
9
|
-
// Cache of compiled stringifiers per schema
|
|
10
|
-
const stringifierCache = new Map();
|
|
11
|
-
// Default fast JSON stringifier for generic objects
|
|
12
|
-
const defaultStringifier = (0, fast_json_stringify_1.default)({
|
|
13
|
-
type: 'object',
|
|
14
|
-
additionalProperties: true,
|
|
15
|
-
});
|
|
16
|
-
/**
|
|
17
|
-
* Fast JSON serializer using fast-json-stringify
|
|
18
|
-
* For best performance, use schema-based stringifiers per route
|
|
19
|
-
*/
|
|
20
|
-
function fastJsonStringify(value, schema) {
|
|
21
|
-
if (schema) {
|
|
22
|
-
const schemaKey = JSON.stringify(schema);
|
|
23
|
-
let stringifier = stringifierCache.get(schemaKey);
|
|
24
|
-
if (!stringifier) {
|
|
25
|
-
stringifier = (0, fast_json_stringify_1.default)(schema);
|
|
26
|
-
stringifierCache.set(schemaKey, stringifier);
|
|
27
|
-
}
|
|
28
|
-
return stringifier(value);
|
|
29
|
-
}
|
|
30
|
-
return defaultStringifier(value);
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Get a pre-compiled stringifier for a specific schema
|
|
34
|
-
* Use this in route handlers for maximum performance
|
|
35
|
-
*/
|
|
36
|
-
function getStringifier(schema) {
|
|
37
|
-
const schemaKey = JSON.stringify(schema);
|
|
38
|
-
let stringifier = stringifierCache.get(schemaKey);
|
|
39
|
-
if (!stringifier) {
|
|
40
|
-
stringifier = (0, fast_json_stringify_1.default)(schema);
|
|
41
|
-
stringifierCache.set(schemaKey, stringifier);
|
|
42
|
-
}
|
|
43
|
-
return stringifier;
|
|
44
|
-
}
|