qhttpx 1.9.4 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +28 -35
  3. package/dist/examples/api-server.js +38 -35
  4. package/dist/examples/basic.js +3 -4
  5. package/dist/examples/compression.js +6 -8
  6. package/dist/examples/cors.js +5 -6
  7. package/dist/examples/errors.js +12 -11
  8. package/dist/examples/file-upload.js +4 -6
  9. package/dist/examples/fusion.js +6 -6
  10. package/dist/examples/rate-limiting.js +10 -10
  11. package/dist/examples/validation.js +5 -6
  12. package/dist/examples/websockets.js +3 -4
  13. package/dist/package.json +3 -8
  14. package/dist/src/benchmarks/quantam-users.js +2 -2
  15. package/dist/src/benchmarks/quick-bench.js +57 -0
  16. package/dist/src/benchmarks/simple-json.js +133 -22
  17. package/dist/src/benchmarks/ultra-mode.js +8 -38
  18. package/dist/src/core/context-pool.d.ts +12 -0
  19. package/dist/src/core/context-pool.js +34 -0
  20. package/dist/src/core/fusion.js +0 -2
  21. package/dist/src/core/metrics.d.ts +3 -1
  22. package/dist/src/core/metrics.js +11 -5
  23. package/dist/src/core/scheduler.d.ts +4 -0
  24. package/dist/src/core/scheduler.js +75 -34
  25. package/dist/src/core/scope.d.ts +23 -8
  26. package/dist/src/core/scope.js +53 -14
  27. package/dist/src/core/serializer.d.ts +1 -1
  28. package/dist/src/core/serializer.js +45 -7
  29. package/dist/src/core/server.d.ts +51 -10
  30. package/dist/src/core/server.js +688 -259
  31. package/dist/src/core/timer.d.ts +11 -0
  32. package/dist/src/core/timer.js +29 -0
  33. package/dist/src/core/types.d.ts +41 -13
  34. package/dist/src/core/types.js +6 -6
  35. package/dist/src/index.d.ts +6 -4
  36. package/dist/src/index.js +19 -20
  37. package/dist/src/middleware/security.js +6 -1
  38. package/dist/src/router/radix-tree.d.ts +5 -2
  39. package/dist/src/router/radix-tree.js +58 -14
  40. package/dist/src/router/router.d.ts +5 -2
  41. package/dist/src/router/router.js +80 -63
  42. package/dist/tests/fusion.test.js +4 -4
  43. package/dist/tests/rate-limit.test.js +2 -2
  44. package/dist/tests/schema-routes.test.js +3 -1
  45. package/docs/AEGIS.md +18 -28
  46. package/docs/BENCHMARKS.md +8 -6
  47. package/docs/DATABASE.md +4 -4
  48. package/docs/MIDDLEWARE.md +3 -3
  49. package/docs/ROUTING.md +21 -13
  50. package/docs/VALIDATION.md +9 -31
  51. package/package.json +3 -8
  52. package/binding.gyp +0 -18
  53. package/dist/src/benchmarks/compare-frameworks.js +0 -119
  54. package/dist/src/benchmarks/compare.js +0 -288
  55. package/dist/src/buffer-pool.js +0 -70
  56. package/dist/src/config.js +0 -50
  57. package/dist/src/cookies.js +0 -59
  58. package/dist/src/core/native-adapter.d.ts +0 -11
  59. package/dist/src/core/native-adapter.js +0 -211
  60. package/dist/src/cors.js +0 -66
  61. package/dist/src/logger.js +0 -45
  62. package/dist/src/metrics.js +0 -111
  63. package/dist/src/native/index.d.ts +0 -32
  64. package/dist/src/native/index.js +0 -141
  65. package/dist/src/presets.js +0 -33
  66. package/dist/src/radix-router.js +0 -89
  67. package/dist/src/radix-tree.js +0 -81
  68. package/dist/src/resources.js +0 -25
  69. package/dist/src/router.js +0 -138
  70. package/dist/src/scheduler.js +0 -85
  71. package/dist/src/security.js +0 -69
  72. package/dist/src/server.js +0 -685
  73. package/dist/src/signals.js +0 -31
  74. package/dist/src/static.js +0 -107
  75. package/dist/src/stream.js +0 -71
  76. package/dist/src/tasks.js +0 -87
  77. package/dist/src/testing.js +0 -40
  78. package/dist/src/types.js +0 -19
  79. package/dist/src/utils/testing.js +0 -40
  80. package/dist/src/worker-queue.js +0 -73
  81. package/dist/tests/native-adapter.test.d.ts +0 -1
  82. package/dist/tests/native-adapter.test.js +0 -71
  83. package/prebuilds/darwin-arm64/qhttpx.node +0 -0
  84. package/prebuilds/linux-x64/qhttpx.node +0 -0
  85. package/prebuilds/win32-x64/qhttpx.node +0 -0
  86. package/scripts/install-native.js +0 -26
  87. package/src/native/README.md +0 -31
  88. package/src/native/addon.cc +0 -8
  89. package/src/native/index.ts +0 -158
  90. package/src/native/picohttpparser.c +0 -608
  91. package/src/native/picohttpparser.h +0 -76
  92. package/src/native/server.cc +0 -264
  93. package/src/native/server.h +0 -30
  94. /package/dist/src/benchmarks/{compare.d.ts → quick-bench.d.ts} +0 -0
@@ -1,31 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.attachSignalHandlers = attachSignalHandlers;
4
- function attachSignalHandlers(app, options = {}) {
5
- const signals = options.signals ?? ['SIGINT', 'SIGTERM'];
6
- const timeoutMs = options.timeoutMs ?? 10000;
7
- let shuttingDown = false;
8
- const handler = async (signal) => {
9
- if (shuttingDown) {
10
- return;
11
- }
12
- shuttingDown = true;
13
- console.log(`Received ${signal}, shutting down...`);
14
- const timer = setTimeout(() => {
15
- console.error('Shutdown timed out, forcing exit. (some connections might be lost)');
16
- process.exit(1);
17
- }, timeoutMs);
18
- try {
19
- await app.shutdown();
20
- clearTimeout(timer);
21
- process.exit(0);
22
- }
23
- catch (err) {
24
- console.error('Error during shutdown:', err);
25
- process.exit(1);
26
- }
27
- };
28
- for (const signal of signals) {
29
- process.on(signal, handler);
30
- }
31
- }
@@ -1,107 +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.createStaticMiddleware = createStaticMiddleware;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- function guessContentType(filePath) {
10
- const ext = path_1.default.extname(filePath).toLowerCase();
11
- if (ext === '.html' || ext === '.htm') {
12
- return 'text/html; charset=utf-8';
13
- }
14
- if (ext === '.js') {
15
- return 'application/javascript; charset=utf-8';
16
- }
17
- if (ext === '.css') {
18
- return 'text/css; charset=utf-8';
19
- }
20
- if (ext === '.json') {
21
- return 'application/json; charset=utf-8';
22
- }
23
- if (ext === '.png') {
24
- return 'image/png';
25
- }
26
- if (ext === '.jpg' || ext === '.jpeg') {
27
- return 'image/jpeg';
28
- }
29
- if (ext === '.gif') {
30
- return 'image/gif';
31
- }
32
- if (ext === '.svg') {
33
- return 'image/svg+xml';
34
- }
35
- return 'application/octet-stream';
36
- }
37
- function createStaticMiddleware(options) {
38
- const root = path_1.default.resolve(options.root);
39
- const indexFile = options.index ?? 'index.html';
40
- const fallthrough = options.fallthrough ?? false;
41
- return async (ctx, next) => {
42
- const method = ctx.req.method || 'GET';
43
- if (method !== 'GET' && method !== 'HEAD') {
44
- if (fallthrough) {
45
- await next();
46
- return;
47
- }
48
- ctx.res.statusCode = 405;
49
- ctx.res.setHeader('content-type', 'text/plain; charset=utf-8');
50
- ctx.res.end('Method Not Allowed');
51
- return;
52
- }
53
- let requestPath = ctx.url.pathname || '/';
54
- requestPath = requestPath.replace(/^[/\\]+/, '');
55
- if (requestPath === '') {
56
- requestPath = indexFile;
57
- }
58
- else if (requestPath.endsWith('/')) {
59
- requestPath = requestPath + indexFile;
60
- }
61
- let safePath = path_1.default.normalize(requestPath);
62
- safePath = safePath.replace(/^(\.\.(\/|\\|$))+/, '');
63
- const filePath = path_1.default.join(root, safePath);
64
- let stat;
65
- try {
66
- stat = await fs_1.default.promises.stat(filePath);
67
- }
68
- catch {
69
- if (fallthrough) {
70
- await next();
71
- return;
72
- }
73
- ctx.res.statusCode = 404;
74
- ctx.res.setHeader('content-type', 'text/plain; charset=utf-8');
75
- ctx.res.end('Not Found');
76
- return;
77
- }
78
- if (!stat.isFile()) {
79
- if (fallthrough) {
80
- await next();
81
- return;
82
- }
83
- ctx.res.statusCode = 404;
84
- ctx.res.setHeader('content-type', 'text/plain; charset=utf-8');
85
- ctx.res.end('Not Found');
86
- return;
87
- }
88
- const contentType = guessContentType(filePath);
89
- ctx.res.setHeader('content-type', contentType);
90
- ctx.res.statusCode = 200;
91
- if (method === 'HEAD') {
92
- ctx.res.end();
93
- return;
94
- }
95
- try {
96
- const data = await fs_1.default.promises.readFile(filePath);
97
- ctx.res.end(data);
98
- }
99
- catch {
100
- if (!ctx.res.headersSent) {
101
- ctx.res.statusCode = 500;
102
- ctx.res.setHeader('content-type', 'text/plain; charset=utf-8');
103
- }
104
- ctx.res.end('Internal Server Error');
105
- }
106
- };
107
- }
@@ -1,71 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createSseStream = createSseStream;
4
- exports.sendStream = sendStream;
5
- function createSseStream(ctx, options = {}) {
6
- const res = ctx.res;
7
- if (!res.headersSent) {
8
- res.statusCode = 200;
9
- res.setHeader('content-type', 'text/event-stream; charset=utf-8');
10
- res.setHeader('cache-control', 'no-cache');
11
- res.setHeader('connection', 'keep-alive');
12
- }
13
- const anyRes = res;
14
- if (anyRes.flushHeaders) {
15
- anyRes.flushHeaders();
16
- }
17
- if (typeof options.retryMs === 'number') {
18
- res.write(`retry: ${options.retryMs}\n\n`);
19
- }
20
- const send = (data, event) => {
21
- if (res.writableEnded) {
22
- return;
23
- }
24
- const payload = typeof data === 'string' ? data : JSON.stringify(data);
25
- let chunk = '';
26
- if (event) {
27
- chunk += `event: ${event}\n`;
28
- }
29
- chunk += `data: ${payload}\n\n`;
30
- res.write(chunk);
31
- if (anyRes.flush) {
32
- anyRes.flush();
33
- }
34
- };
35
- const close = () => {
36
- if (!res.writableEnded) {
37
- res.end();
38
- }
39
- };
40
- return { send, close };
41
- }
42
- function sendStream(ctx, stream, options = {}) {
43
- const res = ctx.res;
44
- if (!res.headersSent) {
45
- if (options.status !== undefined) {
46
- res.statusCode = options.status;
47
- }
48
- if (options.contentType) {
49
- res.setHeader('content-type', options.contentType);
50
- }
51
- }
52
- return new Promise((resolve, reject) => {
53
- stream.on('error', (err) => {
54
- if (!res.headersSent) {
55
- res.statusCode = 500;
56
- res.setHeader('content-type', 'text/plain; charset=utf-8');
57
- }
58
- if (!res.writableEnded) {
59
- res.end('Internal Server Error');
60
- }
61
- reject(err);
62
- });
63
- stream.on('end', () => {
64
- if (!res.writableEnded) {
65
- res.end();
66
- }
67
- resolve();
68
- });
69
- stream.pipe(res, { end: false });
70
- });
71
- }
package/dist/src/tasks.js DELETED
@@ -1,87 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TaskEngine = void 0;
4
- class TaskEngine {
5
- constructor(scheduler) {
6
- this.tasks = new Map();
7
- this.registeredTasksCount = 0;
8
- this.totalEnqueued = 0;
9
- this.totalCompleted = 0;
10
- this.totalFailed = 0;
11
- this.totalOverloaded = 0;
12
- this.totalRetried = 0;
13
- this.scheduler = scheduler;
14
- }
15
- register(name, handler, options = {}) {
16
- if (!this.tasks.has(name)) {
17
- this.registeredTasksCount += 1;
18
- }
19
- this.tasks.set(name, {
20
- name,
21
- handler,
22
- options,
23
- });
24
- }
25
- async enqueue(name, payload) {
26
- const def = this.tasks.get(name);
27
- if (!def) {
28
- throw new Error(`Task "${name}" is not registered`);
29
- }
30
- this.totalEnqueued += 1;
31
- await this.executeWithRetry(def, payload);
32
- }
33
- getMetrics() {
34
- return {
35
- registeredTasks: this.registeredTasksCount,
36
- totalEnqueued: this.totalEnqueued,
37
- totalCompleted: this.totalCompleted,
38
- totalFailed: this.totalFailed,
39
- totalOverloaded: this.totalOverloaded,
40
- totalRetried: this.totalRetried,
41
- };
42
- }
43
- async executeWithRetry(def, payload) {
44
- const maxRetries = def.options.maxRetries ?? 0;
45
- const backoffMs = def.options.backoffMs ?? 0;
46
- let attempt = 0;
47
- for (;;) {
48
- let overloaded = false;
49
- let error;
50
- await this.scheduler.run(async () => {
51
- try {
52
- await def.handler(payload);
53
- }
54
- catch (err) {
55
- error = err;
56
- }
57
- }, {
58
- onOverloaded: () => {
59
- overloaded = true;
60
- },
61
- });
62
- if (!overloaded && !error) {
63
- this.totalCompleted += 1;
64
- return;
65
- }
66
- if (attempt >= maxRetries) {
67
- if (error) {
68
- this.totalFailed += 1;
69
- throw error;
70
- }
71
- if (overloaded) {
72
- this.totalOverloaded += 1;
73
- throw new Error(`Task "${def.name}" overloaded`);
74
- }
75
- return;
76
- }
77
- attempt += 1;
78
- this.totalRetried += 1;
79
- if (backoffMs > 0) {
80
- await new Promise((resolve) => {
81
- setTimeout(resolve, backoffMs);
82
- });
83
- }
84
- }
85
- }
86
- }
87
- exports.TaskEngine = TaskEngine;
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createTestClient = createTestClient;
4
- async function createTestClient(app) {
5
- const { port } = await app.listen(0, '127.0.0.1');
6
- const baseUrl = `http://127.0.0.1:${port}`;
7
- const request = async (method, path, body, extraHeaders = {}) => {
8
- const headers = { ...extraHeaders };
9
- const init = {
10
- method,
11
- headers,
12
- };
13
- if (body !== undefined) {
14
- if (typeof body === 'string') {
15
- init.body = body;
16
- }
17
- else if (body instanceof Uint8Array || Buffer.isBuffer(body)) {
18
- init.body = body;
19
- }
20
- else {
21
- init.body = JSON.stringify(body);
22
- if (!('content-type' in headers)) {
23
- headers['content-type'] = 'application/json';
24
- }
25
- }
26
- }
27
- return fetch(`${baseUrl}${path}`, init);
28
- };
29
- return {
30
- get: (path, headers) => request('GET', path, undefined, headers),
31
- post: (path, body, headers) => request('POST', path, body, headers),
32
- put: (path, body, headers) => request('PUT', path, body, headers),
33
- delete: (path, headers) => request('DELETE', path, undefined, headers),
34
- close: async () => {
35
- await app.close();
36
- },
37
- app,
38
- url: baseUrl,
39
- };
40
- }
package/dist/src/types.js DELETED
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpError = exports.RoutePriority = void 0;
4
- var RoutePriority;
5
- (function (RoutePriority) {
6
- RoutePriority["CRITICAL"] = "critical";
7
- RoutePriority["STANDARD"] = "standard";
8
- RoutePriority["BEST_EFFORT"] = "best-effort";
9
- })(RoutePriority || (exports.RoutePriority = RoutePriority = {}));
10
- class HttpError extends Error {
11
- constructor(status, message, options = {}) {
12
- super(message ?? 'HTTP Error');
13
- this.status = status;
14
- this.code = options.code;
15
- this.details = options.details;
16
- Object.setPrototypeOf(this, new.target.prototype);
17
- }
18
- }
19
- exports.HttpError = HttpError;
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createTestClient = createTestClient;
4
- async function createTestClient(app) {
5
- const { port } = await app.listen(0, '127.0.0.1');
6
- const baseUrl = `http://127.0.0.1:${port}`;
7
- const request = async (method, path, body, extraHeaders = {}) => {
8
- const headers = { ...extraHeaders };
9
- const init = {
10
- method,
11
- headers,
12
- };
13
- if (body !== undefined) {
14
- if (typeof body === 'string') {
15
- init.body = body;
16
- }
17
- else if (body instanceof Uint8Array || Buffer.isBuffer(body)) {
18
- init.body = body;
19
- }
20
- else {
21
- init.body = JSON.stringify(body);
22
- if (!('content-type' in headers)) {
23
- headers['content-type'] = 'application/json';
24
- }
25
- }
26
- }
27
- return fetch(`${baseUrl}${path}`, init);
28
- };
29
- return {
30
- get: (path, headers) => request('GET', path, undefined, headers),
31
- post: (path, body, headers) => request('POST', path, body, headers),
32
- put: (path, body, headers) => request('PUT', path, body, headers),
33
- delete: (path, headers) => request('DELETE', path, undefined, headers),
34
- close: async () => {
35
- await app.close();
36
- },
37
- app,
38
- url: baseUrl,
39
- };
40
- }
@@ -1,73 +0,0 @@
1
- "use strict";
2
- /**
3
- * Lock-free (or lock-minimal) work queue for per-worker task distribution.
4
- * Uses a simple ring buffer for high throughput.
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.WorkerQueue = void 0;
8
- class WorkerQueue {
9
- constructor(capacity = 1024) {
10
- this.writeIndex = 0;
11
- this.readIndex = 0;
12
- this.size = 0;
13
- if (capacity <= 0 || !Number.isInteger(capacity)) {
14
- throw new Error('Capacity must be a positive integer');
15
- }
16
- // Ensure capacity is a power of 2 for efficient modulo with bitmask
17
- this.capacity = Math.pow(2, Math.ceil(Math.log2(capacity)));
18
- this.buffer = new Array(this.capacity);
19
- }
20
- /**
21
- * Enqueue a work item. Returns true if successful, false if queue is full.
22
- */
23
- enqueue(item) {
24
- if (this.size >= this.capacity) {
25
- return false;
26
- }
27
- this.buffer[this.writeIndex] = item;
28
- this.writeIndex = (this.writeIndex + 1) & (this.capacity - 1);
29
- this.size += 1;
30
- return true;
31
- }
32
- /**
33
- * Dequeue a work item. Returns undefined if queue is empty.
34
- */
35
- dequeue() {
36
- if (this.size <= 0) {
37
- return undefined;
38
- }
39
- const item = this.buffer[this.readIndex];
40
- this.buffer[this.readIndex] = undefined;
41
- this.readIndex = (this.readIndex + 1) & (this.capacity - 1);
42
- this.size -= 1;
43
- return item;
44
- }
45
- /**
46
- * Peek at the next item without removing it.
47
- */
48
- peek() {
49
- if (this.size <= 0) {
50
- return undefined;
51
- }
52
- return this.buffer[this.readIndex];
53
- }
54
- /**
55
- * Check if the queue is empty.
56
- */
57
- isEmpty() {
58
- return this.size === 0;
59
- }
60
- /**
61
- * Get the current size of the queue.
62
- */
63
- getSize() {
64
- return this.size;
65
- }
66
- /**
67
- * Get the capacity of the queue.
68
- */
69
- getCapacity() {
70
- return this.capacity;
71
- }
72
- }
73
- exports.WorkerQueue = WorkerQueue;
@@ -1 +0,0 @@
1
- export {};
@@ -1,71 +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
- const vitest_1 = require("vitest");
7
- const native_adapter_1 = require("../src/core/native-adapter");
8
- const index_1 = require("../src/index");
9
- const net_1 = __importDefault(require("net"));
10
- // Mock the NativeServer module
11
- vitest_1.vi.mock('../src/native', () => {
12
- return {
13
- NativeServer: class MockNativeServer {
14
- constructor() {
15
- this.isAvailable = true;
16
- }
17
- parse(buffer) {
18
- const str = buffer.toString();
19
- if (str.includes('GET / HTTP/1.1')) {
20
- return {
21
- method: 'GET',
22
- path: '/',
23
- version: 1,
24
- headers: { host: 'localhost' },
25
- bodyOffset: str.indexOf('\r\n\r\n') + 4
26
- };
27
- }
28
- return undefined;
29
- }
30
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
- createResponse(statusCode, headers, body) {
32
- return Buffer.from(`HTTP/1.1 ${statusCode} OK\r\n\r\n${body || ''}`);
33
- }
34
- }
35
- };
36
- });
37
- (0, vitest_1.describe)('NativeAdapter', () => {
38
- let app;
39
- let adapter;
40
- let server;
41
- let port = 0;
42
- (0, vitest_1.beforeEach)(() => {
43
- app = (0, index_1.createHttpApp)();
44
- adapter = new native_adapter_1.NativeAdapter(app);
45
- });
46
- (0, vitest_1.afterEach)(async () => {
47
- if (server) {
48
- await new Promise(resolve => server.close(() => resolve()));
49
- }
50
- });
51
- (0, vitest_1.it)('should handle request using native parser mock', async () => {
52
- app.get('/', ({ res }) => { res.end('Native Works'); });
53
- await new Promise((resolve) => {
54
- server = adapter.listen(0, () => {
55
- port = server.address().port;
56
- resolve();
57
- });
58
- });
59
- const socket = net_1.default.createConnection(port);
60
- const responsePromise = new Promise((resolve) => {
61
- socket.on('data', (data) => {
62
- resolve(data.toString());
63
- socket.end();
64
- });
65
- });
66
- socket.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n');
67
- const response = await responsePromise;
68
- (0, vitest_1.expect)(response).toContain('HTTP/1.1 200 OK');
69
- (0, vitest_1.expect)(response).toContain('Native Works');
70
- });
71
- });
Binary file
Binary file
Binary file
@@ -1,26 +0,0 @@
1
- const { execSync } = require('child_process');
2
- const fs = require('fs');
3
- const path = require('path');
4
-
5
- // Graceful Native Build Strategy
6
- // This script attempts to build the native addon but swallows errors
7
- // to ensure installation succeeds even on environments without C++ tools.
8
-
9
- try {
10
- // Check if prebuilds exist (optional optimization)
11
- // But usually we want to try building if we are installing from source/npm
12
-
13
- console.log('QHTTPX: Attempting native compilation...');
14
-
15
- // Use node-gyp directly. It should be available in npm environment.
16
- // We inherit stdio so user can see progress/errors if they care,
17
- // but we catch the error to prevent install failure.
18
- execSync('node-gyp rebuild', { stdio: 'inherit' });
19
-
20
- console.log('QHTTPX: Native compilation successful.');
21
- } catch (error) {
22
- console.log('QHTTPX: Native compilation failed.');
23
- console.log('QHTTPX: Falling back to pure JavaScript/WASM adapter.');
24
- // Exit with 0 to allow installation to proceed
25
- process.exit(0);
26
- }
@@ -1,31 +0,0 @@
1
- # QHTTPX Native Addon
2
-
3
- This directory contains the C++ native addon for QHTTPX to accelerate HTTP parsing and response generation.
4
-
5
- ## Prerequisites
6
-
7
- To build this addon, you need:
8
- - **Windows**: Visual Studio Build Tools (Desktop development with C++).
9
- - **Linux/macOS**: Python 3, make, and a C++ compiler (GCC/Clang).
10
-
11
- ## Building
12
-
13
- The build is handled automatically by `npm install` if `node-gyp` and build tools are present.
14
-
15
- To manually rebuild:
16
- ```bash
17
- npx node-gyp rebuild
18
- ```
19
-
20
- ## Structure
21
-
22
- - `addon.cc`: Entry point, registers the module.
23
- - `server.cc`: `NativeServer` class implementation.
24
- - `picohttpparser.c/h`: The HTTP parser library (vendored).
25
- - `index.ts`: TypeScript wrapper and fallback logic.
26
-
27
- ## Usage
28
-
29
- The `NativeAdapter` in `src/core/native-adapter.ts` automatically detects if the native addon is available.
30
- If available, it uses `net.Server` + `NativeServer` for handling requests.
31
- If not, it falls back to the standard `http.Server`.
@@ -1,8 +0,0 @@
1
- #include <napi.h>
2
- #include "server.h"
3
-
4
- Napi::Object InitAll(Napi::Env env, Napi::Object exports) {
5
- return NativeServer::Init(env, exports);
6
- }
7
-
8
- NODE_API_MODULE(qhttpx_native, InitAll)