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.
Files changed (206) hide show
  1. package/package.json +12 -3
  2. package/prebuilds/darwin-arm64/qhttpx.node +0 -0
  3. package/prebuilds/linux-x64/qhttpx.node +0 -0
  4. package/prebuilds/win32-x64/qhttpx.node +0 -0
  5. package/src/native/index.ts +104 -24
  6. package/src/native/picohttpparser.h +5 -0
  7. package/src/native/server.cc +2 -0
  8. package/dist/examples/api-server.d.ts +0 -1
  9. package/dist/examples/api-server.js +0 -77
  10. package/dist/examples/basic.d.ts +0 -1
  11. package/dist/examples/basic.js +0 -10
  12. package/dist/examples/compression.d.ts +0 -1
  13. package/dist/examples/compression.js +0 -17
  14. package/dist/examples/cors.d.ts +0 -1
  15. package/dist/examples/cors.js +0 -19
  16. package/dist/examples/errors.d.ts +0 -1
  17. package/dist/examples/errors.js +0 -25
  18. package/dist/examples/file-upload.d.ts +0 -1
  19. package/dist/examples/file-upload.js +0 -24
  20. package/dist/examples/fusion.d.ts +0 -1
  21. package/dist/examples/fusion.js +0 -21
  22. package/dist/examples/rate-limiting.d.ts +0 -1
  23. package/dist/examples/rate-limiting.js +0 -17
  24. package/dist/examples/validation.d.ts +0 -1
  25. package/dist/examples/validation.js +0 -23
  26. package/dist/examples/websockets.d.ts +0 -1
  27. package/dist/examples/websockets.js +0 -20
  28. package/dist/package.json +0 -101
  29. package/dist/src/benchmarks/quantam-users.d.ts +0 -1
  30. package/dist/src/benchmarks/quantam-users.js +0 -56
  31. package/dist/src/benchmarks/simple-json.d.ts +0 -1
  32. package/dist/src/benchmarks/simple-json.js +0 -60
  33. package/dist/src/benchmarks/ultra-mode.d.ts +0 -1
  34. package/dist/src/benchmarks/ultra-mode.js +0 -94
  35. package/dist/src/cli/index.d.ts +0 -2
  36. package/dist/src/cli/index.js +0 -222
  37. package/dist/src/client/index.d.ts +0 -17
  38. package/dist/src/client/index.js +0 -72
  39. package/dist/src/core/batch.d.ts +0 -24
  40. package/dist/src/core/batch.js +0 -97
  41. package/dist/src/core/body-parser.d.ts +0 -15
  42. package/dist/src/core/body-parser.js +0 -121
  43. package/dist/src/core/buffer-pool.d.ts +0 -41
  44. package/dist/src/core/buffer-pool.js +0 -70
  45. package/dist/src/core/config.d.ts +0 -7
  46. package/dist/src/core/config.js +0 -50
  47. package/dist/src/core/errors.d.ts +0 -34
  48. package/dist/src/core/errors.js +0 -70
  49. package/dist/src/core/fusion.d.ts +0 -14
  50. package/dist/src/core/fusion.js +0 -183
  51. package/dist/src/core/logger.d.ts +0 -22
  52. package/dist/src/core/logger.js +0 -49
  53. package/dist/src/core/metrics.d.ts +0 -45
  54. package/dist/src/core/metrics.js +0 -111
  55. package/dist/src/core/native-adapter.d.ts +0 -11
  56. package/dist/src/core/native-adapter.js +0 -211
  57. package/dist/src/core/resources.d.ts +0 -9
  58. package/dist/src/core/resources.js +0 -25
  59. package/dist/src/core/scheduler.d.ts +0 -34
  60. package/dist/src/core/scheduler.js +0 -85
  61. package/dist/src/core/scope.d.ts +0 -26
  62. package/dist/src/core/scope.js +0 -68
  63. package/dist/src/core/serializer.d.ts +0 -10
  64. package/dist/src/core/serializer.js +0 -44
  65. package/dist/src/core/server.d.ts +0 -138
  66. package/dist/src/core/server.js +0 -1082
  67. package/dist/src/core/stream.d.ts +0 -15
  68. package/dist/src/core/stream.js +0 -71
  69. package/dist/src/core/tasks.d.ts +0 -29
  70. package/dist/src/core/tasks.js +0 -87
  71. package/dist/src/core/types.d.ts +0 -173
  72. package/dist/src/core/types.js +0 -19
  73. package/dist/src/core/websocket.d.ts +0 -25
  74. package/dist/src/core/websocket.js +0 -86
  75. package/dist/src/core/worker-queue.d.ts +0 -41
  76. package/dist/src/core/worker-queue.js +0 -73
  77. package/dist/src/database/adapters/memory.d.ts +0 -21
  78. package/dist/src/database/adapters/memory.js +0 -90
  79. package/dist/src/database/adapters/mongo.d.ts +0 -11
  80. package/dist/src/database/adapters/mongo.js +0 -141
  81. package/dist/src/database/adapters/postgres.d.ts +0 -10
  82. package/dist/src/database/adapters/postgres.js +0 -111
  83. package/dist/src/database/adapters/sqlite.d.ts +0 -10
  84. package/dist/src/database/adapters/sqlite.js +0 -42
  85. package/dist/src/database/coalescer.d.ts +0 -14
  86. package/dist/src/database/coalescer.js +0 -134
  87. package/dist/src/database/manager.d.ts +0 -35
  88. package/dist/src/database/manager.js +0 -87
  89. package/dist/src/database/types.d.ts +0 -20
  90. package/dist/src/database/types.js +0 -2
  91. package/dist/src/index.d.ts +0 -50
  92. package/dist/src/index.js +0 -91
  93. package/dist/src/middleware/compression.d.ts +0 -2
  94. package/dist/src/middleware/compression.js +0 -133
  95. package/dist/src/middleware/cors.d.ts +0 -2
  96. package/dist/src/middleware/cors.js +0 -66
  97. package/dist/src/middleware/presets.d.ts +0 -16
  98. package/dist/src/middleware/presets.js +0 -52
  99. package/dist/src/middleware/rate-limit.d.ts +0 -14
  100. package/dist/src/middleware/rate-limit.js +0 -83
  101. package/dist/src/middleware/security.d.ts +0 -21
  102. package/dist/src/middleware/security.js +0 -69
  103. package/dist/src/middleware/static.d.ts +0 -11
  104. package/dist/src/middleware/static.js +0 -191
  105. package/dist/src/native/index.d.ts +0 -29
  106. package/dist/src/native/index.js +0 -64
  107. package/dist/src/openapi/generator.d.ts +0 -19
  108. package/dist/src/openapi/generator.js +0 -149
  109. package/dist/src/router/radix-router.d.ts +0 -18
  110. package/dist/src/router/radix-router.js +0 -89
  111. package/dist/src/router/radix-tree.d.ts +0 -18
  112. package/dist/src/router/radix-tree.js +0 -131
  113. package/dist/src/router/router.d.ts +0 -34
  114. package/dist/src/router/router.js +0 -186
  115. package/dist/src/testing/index.d.ts +0 -25
  116. package/dist/src/testing/index.js +0 -84
  117. package/dist/src/utils/cookies.d.ts +0 -3
  118. package/dist/src/utils/cookies.js +0 -59
  119. package/dist/src/utils/logger.d.ts +0 -12
  120. package/dist/src/utils/logger.js +0 -45
  121. package/dist/src/utils/signals.d.ts +0 -6
  122. package/dist/src/utils/signals.js +0 -31
  123. package/dist/src/utils/sse.d.ts +0 -6
  124. package/dist/src/utils/sse.js +0 -32
  125. package/dist/src/validation/index.d.ts +0 -3
  126. package/dist/src/validation/index.js +0 -19
  127. package/dist/src/validation/simple.d.ts +0 -5
  128. package/dist/src/validation/simple.js +0 -102
  129. package/dist/src/validation/types.d.ts +0 -32
  130. package/dist/src/validation/types.js +0 -12
  131. package/dist/src/validation/zod.d.ts +0 -4
  132. package/dist/src/validation/zod.js +0 -18
  133. package/dist/src/views/index.d.ts +0 -1
  134. package/dist/src/views/index.js +0 -17
  135. package/dist/src/views/types.d.ts +0 -3
  136. package/dist/src/views/types.js +0 -2
  137. package/dist/tests/adapters.test.d.ts +0 -1
  138. package/dist/tests/adapters.test.js +0 -106
  139. package/dist/tests/batch.test.d.ts +0 -1
  140. package/dist/tests/batch.test.js +0 -117
  141. package/dist/tests/body-parser.test.d.ts +0 -1
  142. package/dist/tests/body-parser.test.js +0 -52
  143. package/dist/tests/compression-sse.test.d.ts +0 -1
  144. package/dist/tests/compression-sse.test.js +0 -87
  145. package/dist/tests/cookies.test.d.ts +0 -1
  146. package/dist/tests/cookies.test.js +0 -63
  147. package/dist/tests/cors.test.d.ts +0 -1
  148. package/dist/tests/cors.test.js +0 -55
  149. package/dist/tests/database.test.d.ts +0 -1
  150. package/dist/tests/database.test.js +0 -80
  151. package/dist/tests/dx.test.d.ts +0 -1
  152. package/dist/tests/dx.test.js +0 -114
  153. package/dist/tests/ecosystem.test.d.ts +0 -1
  154. package/dist/tests/ecosystem.test.js +0 -133
  155. package/dist/tests/features.test.d.ts +0 -1
  156. package/dist/tests/features.test.js +0 -47
  157. package/dist/tests/fusion.test.d.ts +0 -1
  158. package/dist/tests/fusion.test.js +0 -92
  159. package/dist/tests/http-basic.test.d.ts +0 -1
  160. package/dist/tests/http-basic.test.js +0 -124
  161. package/dist/tests/logger.test.d.ts +0 -1
  162. package/dist/tests/logger.test.js +0 -33
  163. package/dist/tests/middleware.test.d.ts +0 -1
  164. package/dist/tests/middleware.test.js +0 -109
  165. package/dist/tests/native-adapter.test.d.ts +0 -1
  166. package/dist/tests/native-adapter.test.js +0 -71
  167. package/dist/tests/observability.test.d.ts +0 -1
  168. package/dist/tests/observability.test.js +0 -59
  169. package/dist/tests/openapi.test.d.ts +0 -1
  170. package/dist/tests/openapi.test.js +0 -64
  171. package/dist/tests/plugin.test.d.ts +0 -1
  172. package/dist/tests/plugin.test.js +0 -65
  173. package/dist/tests/plugins.test.d.ts +0 -1
  174. package/dist/tests/plugins.test.js +0 -71
  175. package/dist/tests/rate-limit.test.d.ts +0 -1
  176. package/dist/tests/rate-limit.test.js +0 -77
  177. package/dist/tests/resources.test.d.ts +0 -1
  178. package/dist/tests/resources.test.js +0 -47
  179. package/dist/tests/scheduler.test.d.ts +0 -1
  180. package/dist/tests/scheduler.test.js +0 -46
  181. package/dist/tests/schema-routes.test.d.ts +0 -1
  182. package/dist/tests/schema-routes.test.js +0 -77
  183. package/dist/tests/security.test.d.ts +0 -1
  184. package/dist/tests/security.test.js +0 -83
  185. package/dist/tests/server-db.test.d.ts +0 -1
  186. package/dist/tests/server-db.test.js +0 -72
  187. package/dist/tests/smoke.test.d.ts +0 -1
  188. package/dist/tests/smoke.test.js +0 -10
  189. package/dist/tests/sqlite-fusion.test.d.ts +0 -1
  190. package/dist/tests/sqlite-fusion.test.js +0 -92
  191. package/dist/tests/static.test.d.ts +0 -1
  192. package/dist/tests/static.test.js +0 -102
  193. package/dist/tests/stream.test.d.ts +0 -1
  194. package/dist/tests/stream.test.js +0 -44
  195. package/dist/tests/task-metrics.test.d.ts +0 -1
  196. package/dist/tests/task-metrics.test.js +0 -53
  197. package/dist/tests/tasks.test.d.ts +0 -1
  198. package/dist/tests/tasks.test.js +0 -62
  199. package/dist/tests/testing.test.d.ts +0 -1
  200. package/dist/tests/testing.test.js +0 -47
  201. package/dist/tests/validation.test.d.ts +0 -1
  202. package/dist/tests/validation.test.js +0 -107
  203. package/dist/tests/websocket.test.d.ts +0 -1
  204. package/dist/tests/websocket.test.js +0 -146
  205. package/dist/vitest.config.d.ts +0 -2
  206. package/dist/vitest.config.js +0 -9
@@ -1,124 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const index_1 = require("../src/index");
5
- (0, vitest_1.describe)('QHTTPX minimal HTTP runtime', () => {
6
- let app;
7
- (0, vitest_1.afterEach)(async () => {
8
- if (app) {
9
- await app.close();
10
- app = undefined;
11
- }
12
- });
13
- (0, vitest_1.it)('handles GET / and returns JSON', async () => {
14
- app = new index_1.QHTTPX();
15
- app.get('/', (ctx) => {
16
- ctx.json({ message: 'Hello from QHTTPX' });
17
- });
18
- const { port } = await app.listen(0, '127.0.0.1');
19
- const response = await fetch(`http://127.0.0.1:${port}/`);
20
- (0, vitest_1.expect)(response.status).toBe(200);
21
- const json = (await response.json());
22
- (0, vitest_1.expect)(json.message).toBe('Hello from QHTTPX');
23
- });
24
- (0, vitest_1.it)('returns 404 for unknown route', async () => {
25
- app = new index_1.QHTTPX();
26
- const { port } = await app.listen(0, '127.0.0.1');
27
- const response = await fetch(`http://127.0.0.1:${port}/unknown`);
28
- (0, vitest_1.expect)(response.status).toBe(404);
29
- });
30
- (0, vitest_1.it)('supports params and query parsing', async () => {
31
- app = new index_1.QHTTPX();
32
- app.get('/users/:id', (ctx) => {
33
- ctx.json({
34
- id: ctx.params.id,
35
- q: ctx.query.q,
36
- });
37
- });
38
- const { port } = await app.listen(0, '127.0.0.1');
39
- const response = await fetch(`http://127.0.0.1:${port}/users/123?q=test`);
40
- (0, vitest_1.expect)(response.status).toBe(200);
41
- const json = (await response.json());
42
- (0, vitest_1.expect)(json.id).toBe('123');
43
- (0, vitest_1.expect)(json.q).toBe('test');
44
- });
45
- (0, vitest_1.it)('parses JSON body for POST', async () => {
46
- app = new index_1.QHTTPX();
47
- app.post('/echo', (ctx) => {
48
- ctx.json({ body: ctx.body });
49
- });
50
- const { port } = await app.listen(0, '127.0.0.1');
51
- const response = await fetch(`http://127.0.0.1:${port}/echo`, {
52
- method: 'POST',
53
- headers: {
54
- 'content-type': 'application/json',
55
- },
56
- body: JSON.stringify({ hello: 'world' }),
57
- });
58
- (0, vitest_1.expect)(response.status).toBe(200);
59
- const json = (await response.json());
60
- (0, vitest_1.expect)(json.body.hello).toBe('world');
61
- });
62
- (0, vitest_1.it)('returns 400 for invalid JSON body', async () => {
63
- app = new index_1.QHTTPX();
64
- const { port } = await app.listen(0, '127.0.0.1');
65
- app.post('/echo', (ctx) => {
66
- ctx.json({ body: ctx.body });
67
- });
68
- const response = await fetch(`http://127.0.0.1:${port}/echo`, {
69
- method: 'POST',
70
- headers: {
71
- 'content-type': 'application/json',
72
- },
73
- body: '{ invalid',
74
- });
75
- (0, vitest_1.expect)(response.status).toBe(400);
76
- const text = await response.text();
77
- (0, vitest_1.expect)(text).toBe('Invalid JSON');
78
- });
79
- (0, vitest_1.it)('enforces maxBodyBytes with 413 status', async () => {
80
- app = new index_1.QHTTPX({ maxBodyBytes: 8 });
81
- app.post('/echo', (ctx) => {
82
- ctx.json({ body: ctx.body });
83
- });
84
- const { port } = await app.listen(0, '127.0.0.1');
85
- const response = await fetch(`http://127.0.0.1:${port}/echo`, {
86
- method: 'POST',
87
- headers: {
88
- 'content-type': 'application/json',
89
- },
90
- body: JSON.stringify({ hello: 'world' }),
91
- });
92
- (0, vitest_1.expect)(response.status).toBe(413);
93
- const text = await response.text();
94
- (0, vitest_1.expect)(text).toBe('Payload Too Large');
95
- });
96
- (0, vitest_1.it)('enforces maxConcurrency with 503 overload', async () => {
97
- app = new index_1.QHTTPX({ maxConcurrency: 1 });
98
- app.get('/slow', async (ctx) => {
99
- await new Promise((resolve) => {
100
- setTimeout(resolve, 100);
101
- });
102
- ctx.json({ ok: true });
103
- });
104
- const { port } = await app.listen(0, '127.0.0.1');
105
- const url = `http://127.0.0.1:${port}/slow`;
106
- const first = fetch(url);
107
- const second = fetch(url);
108
- const [firstRes, secondRes] = await Promise.all([first, second]);
109
- const statuses = [firstRes.status, secondRes.status].sort();
110
- (0, vitest_1.expect)(statuses).toEqual([200, 503]);
111
- });
112
- (0, vitest_1.it)('applies request timeout with 504 status', async () => {
113
- app = new index_1.QHTTPX({ requestTimeoutMs: 20 });
114
- app.get('/timeout', async (ctx) => {
115
- await new Promise((resolve) => {
116
- setTimeout(resolve, 100);
117
- });
118
- ctx.json({ ok: true });
119
- });
120
- const { port } = await app.listen(0, '127.0.0.1');
121
- const response = await fetch(`http://127.0.0.1:${port}/timeout`);
122
- (0, vitest_1.expect)(response.status).toBe(504);
123
- });
124
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,33 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const src_1 = require("../src");
5
- (0, vitest_1.describe)('Logger middleware', () => {
6
- let app;
7
- (0, vitest_1.afterEach)(async () => {
8
- if (app) {
9
- await app.close();
10
- app = undefined;
11
- }
12
- });
13
- (0, vitest_1.it)('logs basic request information to sink', async () => {
14
- const sink = vitest_1.vi.fn();
15
- app = new src_1.QHTTPX();
16
- app.use((0, src_1.createLoggerMiddleware)({
17
- sink,
18
- }));
19
- app.get('/hello', (ctx) => {
20
- ctx.send('ok');
21
- });
22
- const { port } = await app.listen(0, '127.0.0.1');
23
- const response = await fetch(`http://127.0.0.1:${port}/hello`);
24
- (0, vitest_1.expect)(response.status).toBe(200);
25
- (0, vitest_1.expect)(await response.text()).toBe('ok');
26
- (0, vitest_1.expect)(sink).toHaveBeenCalledTimes(1);
27
- const entry = sink.mock.calls[0][0];
28
- (0, vitest_1.expect)(entry.method).toBe('GET');
29
- (0, vitest_1.expect)(entry.path).toBe('/hello');
30
- (0, vitest_1.expect)(entry.status).toBe(200);
31
- (0, vitest_1.expect)(entry.durationMs).toBeGreaterThanOrEqual(0);
32
- });
33
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,109 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const index_1 = require("../src/index");
5
- (0, vitest_1.describe)('QHTTPX middleware pipeline', () => {
6
- let app;
7
- (0, vitest_1.afterEach)(async () => {
8
- if (app) {
9
- await app.close();
10
- app = undefined;
11
- }
12
- });
13
- (0, vitest_1.it)('runs middleware in order with await next()', async () => {
14
- app = new index_1.QHTTPX();
15
- const calls = [];
16
- app.use(async (ctx, next) => {
17
- calls.push('m1-before');
18
- await next();
19
- calls.push('m1-after');
20
- });
21
- app.use(async (ctx, next) => {
22
- calls.push('m2-before');
23
- await next();
24
- calls.push('m2-after');
25
- });
26
- app.get('/', (ctx) => {
27
- calls.push('handler');
28
- ctx.send('ok');
29
- });
30
- const { port } = await app.listen(0, '127.0.0.1');
31
- const response = await fetch(`http://127.0.0.1:${port}/`);
32
- (0, vitest_1.expect)(response.status).toBe(200);
33
- (0, vitest_1.expect)(calls).toEqual([
34
- 'm1-before',
35
- 'm2-before',
36
- 'handler',
37
- 'm2-after',
38
- 'm1-after',
39
- ]);
40
- });
41
- (0, vitest_1.it)('allows middleware to modify response headers', async () => {
42
- app = new index_1.QHTTPX();
43
- app.use((ctx, next) => {
44
- ctx.res.setHeader('x-powered-by', 'qhttpx');
45
- return next();
46
- });
47
- app.get('/', (ctx) => {
48
- ctx.send('ok');
49
- });
50
- const { port } = await app.listen(0, '127.0.0.1');
51
- const response = await fetch(`http://127.0.0.1:${port}/`);
52
- (0, vitest_1.expect)(response.status).toBe(200);
53
- const header = response.headers.get('x-powered-by');
54
- (0, vitest_1.expect)(header).toBe('qhttpx');
55
- });
56
- (0, vitest_1.it)('supports auth middleware that short-circuits unauthorized requests', async () => {
57
- app = new index_1.QHTTPX();
58
- app.use((ctx, next) => {
59
- const auth = ctx.req.headers['authorization'];
60
- if (auth !== 'Bearer secret') {
61
- ctx.res.statusCode = 401;
62
- ctx.res.end('Unauthorized');
63
- return;
64
- }
65
- return next();
66
- });
67
- app.get('/secure', (ctx) => {
68
- ctx.send('ok');
69
- });
70
- const { port } = await app.listen(0, '127.0.0.1');
71
- const unauthorized = await fetch(`http://127.0.0.1:${port}/secure`);
72
- (0, vitest_1.expect)(unauthorized.status).toBe(401);
73
- const unauthorizedText = await unauthorized.text();
74
- (0, vitest_1.expect)(unauthorizedText).toBe('Unauthorized');
75
- const authorized = await fetch(`http://127.0.0.1:${port}/secure`, {
76
- headers: {
77
- authorization: 'Bearer secret',
78
- },
79
- });
80
- (0, vitest_1.expect)(authorized.status).toBe(200);
81
- const body = await authorized.text();
82
- (0, vitest_1.expect)(body).toBe('ok');
83
- });
84
- (0, vitest_1.it)('supports error-handling middleware that converts errors to JSON', async () => {
85
- app = new index_1.QHTTPX();
86
- app.use(async (ctx, next) => {
87
- try {
88
- await next();
89
- }
90
- catch (err) {
91
- ctx.res.statusCode = 500;
92
- ctx.res.setHeader('content-type', 'application/json; charset=utf-8');
93
- ctx.res.end(JSON.stringify({
94
- error: 'internal',
95
- message: err instanceof Error ? err.message : 'unknown',
96
- }));
97
- }
98
- });
99
- app.get('/boom', () => {
100
- throw new Error('boom');
101
- });
102
- const { port } = await app.listen(0, '127.0.0.1');
103
- const response = await fetch(`http://127.0.0.1:${port}/boom`);
104
- (0, vitest_1.expect)(response.status).toBe(500);
105
- const json = (await response.json());
106
- (0, vitest_1.expect)(json.error).toBe('internal');
107
- (0, vitest_1.expect)(json.message).toBe('boom');
108
- });
109
- });
@@ -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
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,59 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const index_1 = require("../src/index");
5
- (0, vitest_1.describe)('QHTTPX observability and health', () => {
6
- let app;
7
- (0, vitest_1.afterEach)(async () => {
8
- if (app) {
9
- await app.close();
10
- app = undefined;
11
- }
12
- });
13
- (0, vitest_1.it)('exposes a health endpoint with basic info', async () => {
14
- app = new index_1.QHTTPX();
15
- const { port } = await app.listen(0, '127.0.0.1');
16
- const response = await fetch(`http://127.0.0.1:${port}/__qhttpx/health`);
17
- (0, vitest_1.expect)(response.status).toBe(200);
18
- const json = (await response.json());
19
- (0, vitest_1.expect)(json.status).toBe('ok');
20
- (0, vitest_1.expect)(typeof json.name).toBe('string');
21
- (0, vitest_1.expect)(typeof json.version).toBe('string');
22
- (0, vitest_1.expect)(json.workers).toBeGreaterThan(0);
23
- });
24
- (0, vitest_1.it)('exposes metrics for handled requests', async () => {
25
- app = new index_1.QHTTPX();
26
- app.get('/ping', (ctx) => {
27
- ctx.send('pong');
28
- });
29
- const { port } = await app.listen(0, '127.0.0.1');
30
- await fetch(`http://127.0.0.1:${port}/ping`);
31
- await fetch(`http://127.0.0.1:${port}/ping`);
32
- const response = await fetch(`http://127.0.0.1:${port}/__qhttpx/metrics`);
33
- (0, vitest_1.expect)(response.status).toBe(200);
34
- const json = (await response.json());
35
- (0, vitest_1.expect)(json.totalRequests).toBeGreaterThanOrEqual(2);
36
- (0, vitest_1.expect)(json.inFlightRequests).toBeGreaterThanOrEqual(0);
37
- (0, vitest_1.expect)(json.latency.p50 === null || json.latency.p50 >= 0).toBe(true);
38
- (0, vitest_1.expect)(json.memory.rssBytes).toBeGreaterThan(0);
39
- (0, vitest_1.expect)(json.memory.heapUsedBytes).toBeGreaterThan(0);
40
- (0, vitest_1.expect)(json.workers).toBeGreaterThan(0);
41
- });
42
- (0, vitest_1.it)('propagates and generates x-request-id headers', async () => {
43
- app = new index_1.QHTTPX();
44
- app.get('/ping', (ctx) => {
45
- ctx.send('pong');
46
- });
47
- const { port } = await app.listen(0, '127.0.0.1');
48
- const first = await fetch(`http://127.0.0.1:${port}/ping`);
49
- const firstId = first.headers.get('x-request-id');
50
- (0, vitest_1.expect)(firstId === null || firstId.length > 0).toBe(true);
51
- const second = await fetch(`http://127.0.0.1:${port}/ping`, {
52
- headers: {
53
- 'x-request-id': 'custom-id-123',
54
- },
55
- });
56
- const secondId = second.headers.get('x-request-id');
57
- (0, vitest_1.expect)(secondId).toBe('custom-id-123');
58
- });
59
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,64 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const server_1 = require("../src/core/server");
5
- (0, vitest_1.describe)('OpenAPI Generator', () => {
6
- (0, vitest_1.it)('should generate valid OpenAPI spec from routes', () => {
7
- const app = new server_1.QHTTPX();
8
- const userSchema = {
9
- params: {
10
- type: 'object',
11
- properties: {
12
- id: { type: 'string' }
13
- }
14
- },
15
- body: {
16
- type: 'object',
17
- properties: {
18
- name: { type: 'string' },
19
- age: { type: 'number', min: 18 }
20
- }
21
- },
22
- response: {
23
- type: 'object',
24
- properties: {
25
- success: { type: 'boolean' }
26
- }
27
- }
28
- };
29
- app.post('/users/:id', {
30
- schema: userSchema,
31
- handler: (ctx) => { ctx.json({ success: true }); }
32
- });
33
- app.get('/health', (ctx) => { ctx.send('ok'); });
34
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
- const spec = app.getOpenAPI({
36
- info: {
37
- title: 'Test API',
38
- version: '1.0.0'
39
- }
40
- });
41
- // Check basic structure
42
- (0, vitest_1.expect)(spec.openapi).toBe('3.0.0');
43
- (0, vitest_1.expect)(spec.info.title).toBe('Test API');
44
- // Check Path normalization
45
- (0, vitest_1.expect)(spec.paths['/users/{id}']).toBeDefined();
46
- (0, vitest_1.expect)(spec.paths['/health']).toBeDefined();
47
- // Check Operation
48
- const postUser = spec.paths['/users/{id}'].post;
49
- (0, vitest_1.expect)(postUser).toBeDefined();
50
- // Check Params
51
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
- const pathParam = postUser.parameters.find((p) => p.name === 'id');
53
- (0, vitest_1.expect)(pathParam).toBeDefined();
54
- (0, vitest_1.expect)(pathParam.in).toBe('path');
55
- (0, vitest_1.expect)(pathParam.required).toBe(true);
56
- // Check Request Body
57
- const bodySchema = postUser.requestBody.content['application/json'].schema;
58
- (0, vitest_1.expect)(bodySchema.properties.name.type).toBe('string');
59
- (0, vitest_1.expect)(bodySchema.properties.age.minimum).toBe(18);
60
- // Check Response
61
- const responseSchema = postUser.responses['200'].content['application/json'].schema;
62
- (0, vitest_1.expect)(responseSchema.properties.success.type).toBe('boolean');
63
- });
64
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,65 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const server_1 = require("../src/core/server");
5
- (0, vitest_1.describe)('Plugin System', () => {
6
- (0, vitest_1.it)('should register a simple plugin', async () => {
7
- const app = new server_1.QHTTPX();
8
- let pluginRun = false;
9
- const myPlugin = async (scope) => {
10
- pluginRun = true;
11
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
- scope.get('/ping', (ctx) => ctx.json({ pong: true }));
13
- };
14
- await app.register(myPlugin);
15
- (0, vitest_1.expect)(pluginRun).toBe(true);
16
- const { port } = await app.listen(0);
17
- const res = await fetch(`http://localhost:${port}/ping`);
18
- (0, vitest_1.expect)(res.status).toBe(200);
19
- (0, vitest_1.expect)(await res.json()).toEqual({ pong: true });
20
- });
21
- (0, vitest_1.it)('should handle prefixes', async () => {
22
- const app = new server_1.QHTTPX();
23
- const apiPlugin = async (scope) => {
24
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
- scope.get('/users', (ctx) => ctx.json({ users: [] }));
26
- };
27
- // Register with prefix /v1
28
- await app.register(apiPlugin, { prefix: '/v1' });
29
- const { port } = await app.listen(0);
30
- // /v1/users should exist
31
- const res = await fetch(`http://localhost:${port}/v1/users`);
32
- (0, vitest_1.expect)(res.status).toBe(200);
33
- // /users should NOT exist
34
- const res404 = await fetch(`http://localhost:${port}/users`);
35
- (0, vitest_1.expect)(res404.status).toBe(404);
36
- });
37
- (0, vitest_1.it)('should handle nested plugins with concatenated prefixes', async () => {
38
- const app = new server_1.QHTTPX();
39
- const usersPlugin = async (scope) => {
40
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
- scope.get('/list', (ctx) => ctx.json({ list: true }));
42
- };
43
- const v1Plugin = async (scope) => {
44
- // Register nested plugin under /users
45
- await scope.register(usersPlugin, { prefix: '/users' });
46
- };
47
- // Register v1 under /api
48
- await app.register(v1Plugin, { prefix: '/api' });
49
- const { port } = await app.listen(0);
50
- // Result should be /api/users/list
51
- const res = await fetch(`http://localhost:${port}/api/users/list`);
52
- (0, vitest_1.expect)(res.status).toBe(200);
53
- (0, vitest_1.expect)(await res.json()).toEqual({ list: true });
54
- });
55
- (0, vitest_1.it)('should pass options to plugins', async () => {
56
- const app = new server_1.QHTTPX();
57
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
- let receivedOpts;
59
- const configPlugin = async (scope, opts) => {
60
- receivedOpts = opts;
61
- };
62
- await app.register(configPlugin, { prefix: '/a', secret: '123' });
63
- (0, vitest_1.expect)(receivedOpts).toEqual({ prefix: '/a', secret: '123' });
64
- });
65
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,71 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const server_1 = require("../src/core/server");
5
- const testing_1 = require("../src/testing");
6
- (0, vitest_1.describe)('Plugin System', () => {
7
- (0, vitest_1.it)('should register a simple plugin', async () => {
8
- const app = new server_1.QHTTPX();
9
- const myPlugin = (s) => {
10
- const scope = s;
11
- scope.get('/plugin', (ctx) => {
12
- ctx.json({ message: 'Hello from Plugin' });
13
- });
14
- };
15
- await app.register(myPlugin);
16
- const client = (0, testing_1.createTestClient)(app);
17
- const res = await client.get('/plugin');
18
- (0, vitest_1.expect)(res.status).toBe(200);
19
- (0, vitest_1.expect)(await res.json()).toEqual({ message: 'Hello from Plugin' });
20
- await client.stop();
21
- });
22
- (0, vitest_1.it)('should support scoped prefixes', async () => {
23
- const app = new server_1.QHTTPX();
24
- const v1Plugin = (s) => {
25
- const scope = s;
26
- scope.get('/users', (ctx) => {
27
- ctx.json({ version: 'v1' });
28
- });
29
- };
30
- await app.register(v1Plugin, { prefix: '/v1' });
31
- const client = (0, testing_1.createTestClient)(app);
32
- const res = await client.get('/v1/users');
33
- (0, vitest_1.expect)(res.status).toBe(200);
34
- (0, vitest_1.expect)(await res.json()).toEqual({ version: 'v1' });
35
- await client.stop();
36
- });
37
- (0, vitest_1.it)('should support nested plugins', async () => {
38
- const app = new server_1.QHTTPX();
39
- const usersPlugin = (s) => {
40
- const scope = s;
41
- scope.get('/list', (ctx) => {
42
- ctx.json({ users: [] });
43
- });
44
- };
45
- const apiPlugin = async (s) => {
46
- const scope = s;
47
- await scope.register(usersPlugin, { prefix: '/users' });
48
- };
49
- await app.register(apiPlugin, { prefix: '/api' });
50
- const client = (0, testing_1.createTestClient)(app);
51
- const res = await client.get('/api/users/list');
52
- (0, vitest_1.expect)(res.status).toBe(200);
53
- (0, vitest_1.expect)(await res.json()).toEqual({ users: [] });
54
- await client.stop();
55
- });
56
- (0, vitest_1.it)('should support plugin options', async () => {
57
- const app = new server_1.QHTTPX();
58
- const authPlugin = (s, options) => {
59
- const scope = s;
60
- scope.get('/secret', (ctx) => {
61
- ctx.json({ secret: options.secret });
62
- });
63
- };
64
- await app.register(authPlugin, { secret: 'super-secret' });
65
- const client = (0, testing_1.createTestClient)(app);
66
- const res = await client.get('/secret');
67
- (0, vitest_1.expect)(res.status).toBe(200);
68
- (0, vitest_1.expect)(await res.json()).toEqual({ secret: 'super-secret' });
69
- await client.stop();
70
- });
71
- });
@@ -1 +0,0 @@
1
- export {};