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,63 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const cookies_1 = require("../src/utils/cookies");
5
- (0, vitest_1.describe)('Cookie Parsing', () => {
6
- (0, vitest_1.it)('should parse simple cookies', () => {
7
- const header = 'foo=bar; baz=qux';
8
- const result = (0, cookies_1.parseCookies)(header);
9
- (0, vitest_1.expect)(result).toEqual({ foo: 'bar', baz: 'qux' });
10
- });
11
- (0, vitest_1.it)('should handle quoted values', () => {
12
- const header = 'foo="bar"; baz=qux';
13
- // Basic implementation might not strip quotes if not decoding specifically for that,
14
- // but let's see standard behavior. My implementation just decodes URI component.
15
- // 'foo="bar"' split by '=' -> ['foo', '"bar"']. decodeURIComponent('"bar"') -> '"bar"'.
16
- const result = (0, cookies_1.parseCookies)(header);
17
- (0, vitest_1.expect)(result).toEqual({ foo: '"bar"', baz: 'qux' });
18
- });
19
- (0, vitest_1.it)('should handle URL encoded values', () => {
20
- const header = 'foo=Hello%20World';
21
- const result = (0, cookies_1.parseCookies)(header);
22
- (0, vitest_1.expect)(result).toEqual({ foo: 'Hello World' });
23
- });
24
- (0, vitest_1.it)('should handle empty header', () => {
25
- (0, vitest_1.expect)((0, cookies_1.parseCookies)(undefined)).toEqual({});
26
- (0, vitest_1.expect)((0, cookies_1.parseCookies)('')).toEqual({});
27
- });
28
- (0, vitest_1.it)('should ignore cookies without name', () => {
29
- const header = '=bar; baz=qux';
30
- const result = (0, cookies_1.parseCookies)(header);
31
- (0, vitest_1.expect)(result).toEqual({ baz: 'qux' });
32
- });
33
- });
34
- (0, vitest_1.describe)('Cookie Serialization', () => {
35
- (0, vitest_1.it)('should serialize name and value', () => {
36
- const result = (0, cookies_1.serializeCookie)('foo', 'bar');
37
- (0, vitest_1.expect)(result).toBe('foo=bar; Path=/');
38
- });
39
- (0, vitest_1.it)('should encode value', () => {
40
- const result = (0, cookies_1.serializeCookie)('foo', 'Hello World');
41
- (0, vitest_1.expect)(result).toBe('foo=Hello%20World; Path=/');
42
- });
43
- (0, vitest_1.it)('should handle Max-Age', () => {
44
- const result = (0, cookies_1.serializeCookie)('foo', 'bar', { maxAge: 3600 });
45
- (0, vitest_1.expect)(result).toContain('Max-Age=3600');
46
- });
47
- (0, vitest_1.it)('should handle HttpOnly', () => {
48
- const result = (0, cookies_1.serializeCookie)('foo', 'bar', { httpOnly: true });
49
- (0, vitest_1.expect)(result).toContain('HttpOnly');
50
- });
51
- (0, vitest_1.it)('should handle Secure', () => {
52
- const result = (0, cookies_1.serializeCookie)('foo', 'bar', { secure: true });
53
- (0, vitest_1.expect)(result).toContain('Secure');
54
- });
55
- (0, vitest_1.it)('should handle SameSite', () => {
56
- const result = (0, cookies_1.serializeCookie)('foo', 'bar', { sameSite: 'strict' });
57
- (0, vitest_1.expect)(result).toContain('SameSite=Strict');
58
- });
59
- (0, vitest_1.it)('should handle Path', () => {
60
- const result = (0, cookies_1.serializeCookie)('foo', 'bar', { path: '/admin' });
61
- (0, vitest_1.expect)(result).toContain('Path=/admin');
62
- });
63
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,55 +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)('CORS 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)('sets default CORS headers and passes through GET', async () => {
14
- app = new src_1.QHTTPX();
15
- app.use((0, src_1.createCorsMiddleware)());
16
- app.get('/ping', (ctx) => {
17
- ctx.send('pong');
18
- });
19
- const { port } = await app.listen(0, '127.0.0.1');
20
- const response = await fetch(`http://127.0.0.1:${port}/ping`, {
21
- headers: {
22
- origin: 'http://example.com',
23
- },
24
- });
25
- (0, vitest_1.expect)(response.status).toBe(200);
26
- (0, vitest_1.expect)(await response.text()).toBe('pong');
27
- (0, vitest_1.expect)(response.headers.get('access-control-allow-origin')).toBe('*');
28
- });
29
- (0, vitest_1.it)('handles preflight OPTIONS requests', async () => {
30
- app = new src_1.QHTTPX();
31
- app.use((0, src_1.createCorsMiddleware)({
32
- origin: ['http://example.com'],
33
- methods: ['GET', 'POST'],
34
- allowedHeaders: ['content-type'],
35
- maxAgeSeconds: 600,
36
- }));
37
- app.get('/ping', (ctx) => {
38
- ctx.send('pong');
39
- });
40
- const { port } = await app.listen(0, '127.0.0.1');
41
- const response = await fetch(`http://127.0.0.1:${port}/ping`, {
42
- method: 'OPTIONS',
43
- headers: {
44
- origin: 'http://example.com',
45
- 'access-control-request-method': 'GET',
46
- 'access-control-request-headers': 'content-type',
47
- },
48
- });
49
- (0, vitest_1.expect)(response.status).toBe(204);
50
- (0, vitest_1.expect)(response.headers.get('access-control-allow-origin')).toBe('http://example.com');
51
- (0, vitest_1.expect)(response.headers.get('access-control-allow-methods')).toBe('GET, POST');
52
- (0, vitest_1.expect)(response.headers.get('access-control-allow-headers')).toBe('content-type');
53
- (0, vitest_1.expect)(response.headers.get('access-control-max-age')).toBe('600');
54
- });
55
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,80 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const manager_1 = require("../src/database/manager");
5
- const memory_1 = require("../src/database/adapters/memory");
6
- (0, vitest_1.describe)('Database Engine', () => {
7
- let dbManager;
8
- (0, vitest_1.beforeEach)(() => {
9
- // Register the adapter
10
- manager_1.DatabaseManager.registerAdapter('memory', memory_1.MemoryAdapter);
11
- // Initialize manager
12
- dbManager = new manager_1.DatabaseManager({
13
- default: 'main',
14
- connections: {
15
- main: {
16
- type: 'memory',
17
- database: 'test_db'
18
- }
19
- }
20
- });
21
- });
22
- (0, vitest_1.afterEach)(async () => {
23
- await dbManager.disconnect();
24
- });
25
- (0, vitest_1.it)('should connect to the default database', async () => {
26
- const adapter = await dbManager.connect();
27
- (0, vitest_1.expect)(adapter).toBeDefined();
28
- (0, vitest_1.expect)(adapter.isConnected()).toBe(true);
29
- });
30
- (0, vitest_1.it)('should perform CRUD operations with MemoryAdapter', async () => {
31
- const adapter = await dbManager.connect();
32
- // Insert
33
- const user = await adapter.query({
34
- collection: 'users',
35
- action: 'insert',
36
- data: { name: 'John Doe', email: 'john@example.com' }
37
- });
38
- (0, vitest_1.expect)(user).toHaveProperty('id');
39
- (0, vitest_1.expect)(user.name).toBe('John Doe');
40
- // Find
41
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
- const users = await adapter.query({
43
- collection: 'users',
44
- action: 'find',
45
- filter: { name: 'John Doe' }
46
- });
47
- (0, vitest_1.expect)(users).toHaveLength(1);
48
- (0, vitest_1.expect)(users[0].email).toBe('john@example.com');
49
- // Update
50
- const updateCount = await adapter.query({
51
- collection: 'users',
52
- action: 'update',
53
- filter: { name: 'John Doe' },
54
- data: { name: 'John Updated' }
55
- });
56
- (0, vitest_1.expect)(updateCount).toBe(1);
57
- // Verify Update
58
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
- const updatedUsers = await adapter.query({
60
- collection: 'users',
61
- action: 'find',
62
- filter: { name: 'John Updated' }
63
- });
64
- (0, vitest_1.expect)(updatedUsers).toHaveLength(1);
65
- // Delete
66
- const deleteCount = await adapter.query({
67
- collection: 'users',
68
- action: 'delete',
69
- filter: { name: 'John Updated' }
70
- });
71
- (0, vitest_1.expect)(deleteCount).toBe(1);
72
- // Verify Delete
73
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
- const remainingUsers = await adapter.query({
75
- collection: 'users',
76
- action: 'find'
77
- });
78
- (0, vitest_1.expect)(remainingUsers).toHaveLength(0);
79
- });
80
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,114 +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
- const index_2 = require("../src/index");
6
- (0, vitest_1.describe)('Developer Experience (DX) Features', () => {
7
- (0, vitest_1.it)('supports destructured context in route handlers', async () => {
8
- const app = (0, index_1.createHttpApp)();
9
- app.get('/destructure', ({ json, path, query }) => {
10
- json({ path, query, status: 'ok' });
11
- });
12
- const { port } = await app.listen(0, '127.0.0.1');
13
- try {
14
- const response = await fetch(`http://127.0.0.1:${port}/destructure?foo=bar`);
15
- (0, vitest_1.expect)(response.status).toBe(200);
16
- const body = await response.json();
17
- (0, vitest_1.expect)(body).toEqual({
18
- path: '/destructure',
19
- query: { foo: 'bar' },
20
- status: 'ok'
21
- });
22
- }
23
- finally {
24
- await app.close();
25
- }
26
- });
27
- (0, vitest_1.it)('supports destructured context in onError handler', async () => {
28
- const app = (0, index_1.createHttpApp)();
29
- app.get('/error', () => {
30
- throw new Error('Boom');
31
- });
32
- app.onError(({ error, json }) => {
33
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
- json({ error: error.message, handled: true }, 500);
35
- });
36
- const { port } = await app.listen(0, '127.0.0.1');
37
- try {
38
- const response = await fetch(`http://127.0.0.1:${port}/error`);
39
- (0, vitest_1.expect)(response.status).toBe(500);
40
- const body = await response.json();
41
- (0, vitest_1.expect)(body).toEqual({ error: 'Boom', handled: true });
42
- }
43
- finally {
44
- await app.close();
45
- }
46
- });
47
- (0, vitest_1.it)('supports notFound alias', async () => {
48
- const app = (0, index_1.createHttpApp)();
49
- app.notFound(({ json }) => {
50
- json({ error: 'Not Found Custom' }, 404);
51
- });
52
- const { port } = await app.listen(0, '127.0.0.1');
53
- try {
54
- const response = await fetch(`http://127.0.0.1:${port}/missing`);
55
- (0, vitest_1.expect)(response.status).toBe(404);
56
- const body = await response.json();
57
- (0, vitest_1.expect)(body).toEqual({ error: 'Not Found Custom' });
58
- }
59
- finally {
60
- await app.close();
61
- }
62
- });
63
- (0, vitest_1.it)('exports a singleton app instance', () => {
64
- (0, vitest_1.expect)(index_2.app).toBeDefined();
65
- (0, vitest_1.expect)(typeof index_2.app.get).toBe('function');
66
- (0, vitest_1.expect)(typeof index_2.app.listen).toBe('function');
67
- });
68
- (0, vitest_1.it)('supports destructured next in middleware', async () => {
69
- const app = (0, index_1.createHttpApp)();
70
- const calls = [];
71
- // Middleware with destructuring: ({ next })
72
- app.use(async ({ next, req }) => {
73
- calls.push('start');
74
- calls.push(req.method); // Verify req is accessible
75
- if (next)
76
- await next();
77
- calls.push('end');
78
- });
79
- app.get('/', ({ json }) => {
80
- calls.push('handler');
81
- json({ ok: true });
82
- });
83
- const { port } = await app.listen(0, '127.0.0.1');
84
- try {
85
- await fetch(`http://127.0.0.1:${port}/`);
86
- (0, vitest_1.expect)(calls).toEqual(['start', 'GET', 'handler', 'end']);
87
- }
88
- finally {
89
- await app.close();
90
- }
91
- });
92
- (0, vitest_1.it)('supports typed files in context', async () => {
93
- // This is primarily a type check, but we can simulate a file structure
94
- const app = (0, index_1.createHttpApp)();
95
- app.post('/upload', ({ files, json }) => {
96
- // Simulate type access
97
- if (files && files['avatar']) {
98
- const avatar = Array.isArray(files['avatar']) ? files['avatar'][0] : files['avatar'];
99
- json({ filename: avatar.filename, size: avatar.size });
100
- }
101
- else {
102
- json({ error: 'no file' }, 400);
103
- }
104
- });
105
- // Mocking the context directly to test logic without full multipart request (BodyParser is tested elsewhere)
106
- // But we can create a "fake" request if we used the internal methods,
107
- // here we just want to ensure the code compiles and runs if files are present.
108
- // Let's do a full test with createTestClient if possible, or just skip full multipart integration test
109
- // since we updated the types.
110
- // For now, let's just ensure the server runs.
111
- await app.listen(0, '127.0.0.1');
112
- await app.close();
113
- });
114
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,133 +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
- // Mock External Libraries
6
- const mockJose = {
7
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
8
- jwtVerify: async (token, _secret) => {
9
- if (token === 'valid_token')
10
- return { payload: { sub: 'user_123', role: 'admin' } };
11
- throw new Error('Invalid Token');
12
- }
13
- };
14
- const mockRedis = {
15
- get: async (key) => {
16
- if (key === 'cache:page:home')
17
- return '<html>Cached Home</html>';
18
- return null;
19
- },
20
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
21
- set: async (key, val) => 'OK'
22
- };
23
- (0, vitest_1.describe)('SaaS Ecosystem Compatibility', () => {
24
- (0, vitest_1.it)('should allow integration of 3rd party JWT libraries (e.g. jose)', async () => {
25
- const app = new server_1.QHTTPX();
26
- const secret = 'super-secret';
27
- // const token = await new SignJWT({ 'urn:example:claim': true })
28
- // .setProtectedHeader({ alg: 'HS256' })
29
- // .setIssuedAt()
30
- // .setExpirationTime('2h')
31
- // .sign(new TextEncoder().encode(secret));
32
- // 1. Create a custom Authentication Middleware using "jose"
33
- const authMiddleware = async (ctx, next) => {
34
- const authHeader = ctx.req.headers['authorization'];
35
- if (!authHeader) {
36
- ctx.res.statusCode = 401;
37
- ctx.res.end('Unauthorized');
38
- return;
39
- }
40
- try {
41
- const token = authHeader.split(' ')[1];
42
- const { payload } = await mockJose.jwtVerify(token, secret);
43
- // Store user in ctx.state (Standard Pattern)
44
- ctx.state.user = payload;
45
- await next();
46
- }
47
- catch {
48
- ctx.res.statusCode = 403;
49
- ctx.res.end('Forbidden');
50
- }
51
- };
52
- app.use(authMiddleware);
53
- // Protected Route
54
- app.get('/dashboard', async (ctx) => {
55
- // Access the user injected by middleware
56
- const user = ctx.state.user;
57
- ctx.json({ message: `Welcome ${user.sub}`, role: user.role });
58
- });
59
- const { port } = await app.listen(0);
60
- const url = `http://localhost:${port}`;
61
- // Test Valid Token
62
- const res1 = await fetch(`${url}/dashboard`, { headers: { Authorization: 'Bearer valid_token' } });
63
- (0, vitest_1.expect)(res1.status).toBe(200);
64
- const data1 = await res1.json();
65
- (0, vitest_1.expect)(data1).toEqual({ message: 'Welcome user_123', role: 'admin' });
66
- // Test Invalid Token
67
- const res2 = await fetch(`${url}/dashboard`, { headers: { Authorization: 'Bearer bad_token' } });
68
- (0, vitest_1.expect)(res2.status).toBe(403);
69
- await app.close();
70
- });
71
- (0, vitest_1.it)('should allow integration of 3rd party Caching (e.g. Redis)', async () => {
72
- const app = new server_1.QHTTPX();
73
- // 2. Create a Caching Middleware using "redis"
74
- const cacheMiddleware = async (ctx, next) => {
75
- const key = `cache:page:${ctx.url.pathname.replace('/', '')}`;
76
- const cached = await mockRedis.get(key);
77
- if (cached) {
78
- ctx.res.setHeader('X-Cache', 'HIT');
79
- ctx.res.end(cached);
80
- return;
81
- }
82
- ctx.res.setHeader('X-Cache', 'MISS');
83
- await next();
84
- };
85
- app.use(cacheMiddleware);
86
- app.get('/home', async (ctx) => {
87
- ctx.html('<html>Fresh Home</html>');
88
- });
89
- const { port } = await app.listen(0);
90
- const url = `http://localhost:${port}`;
91
- // Test Cache Hit (Mocked)
92
- const res1 = await fetch(`${url}/home`);
93
- (0, vitest_1.expect)(res1.status).toBe(200);
94
- (0, vitest_1.expect)(res1.headers.get('x-cache')).toBe('HIT');
95
- const text1 = await res1.text();
96
- (0, vitest_1.expect)(text1).toBe('<html>Cached Home</html>');
97
- // Test Cache Miss (Mocked for other route)
98
- // Note: In a real app we'd need to intercept res.end to write to redis,
99
- // but for this capability check, reading is enough proof.
100
- await app.close();
101
- });
102
- (0, vitest_1.it)('should allow integration of ORM/DB libraries', async () => {
103
- const app = new server_1.QHTTPX();
104
- // Mock TypeORM/Prisma usage
105
- const db = {
106
- users: {
107
- findMany: async () => [{ id: 1, name: 'Alice' }],
108
- },
109
- };
110
- // Middleware to attach DB to context
111
- app.use(async (ctx, next) => {
112
- // We can attach to ctx.state or extend ctx type if we want
113
- ctx.state.db = db;
114
- await next();
115
- });
116
- app.get('/users', async (ctx) => {
117
- try {
118
- const users = await ctx.state.db.users.findMany();
119
- ctx.res.end(JSON.stringify(users));
120
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
121
- }
122
- catch (err) {
123
- ctx.res.statusCode = 500;
124
- ctx.res.end('DB Error');
125
- }
126
- });
127
- const { port } = await app.listen(0);
128
- const url = `http://localhost:${port}`;
129
- const res = await fetch(`${url}/users`);
130
- (0, vitest_1.expect)(res.status).toBe(200);
131
- await app.close();
132
- });
133
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,47 +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
- const logger_1 = require("../src/core/logger");
6
- const client_1 = require("../src/client");
7
- (0, vitest_1.describe)('Logger', () => {
8
- (0, vitest_1.it)('should initialize with pino', () => {
9
- const logger = new logger_1.Logger({ level: 'info' });
10
- (0, vitest_1.expect)(logger).toBeDefined();
11
- // Check if methods exist (can't easily mock internal pino without spy)
12
- (0, vitest_1.expect)(typeof logger.info).toBe('function');
13
- (0, vitest_1.expect)(typeof logger.error).toBe('function');
14
- });
15
- (0, vitest_1.it)('should be integrated into QHTTPX', () => {
16
- const app = new index_1.QHTTPX();
17
- (0, vitest_1.expect)(app.logger).toBeDefined();
18
- (0, vitest_1.expect)(app.logger instanceof logger_1.Logger).toBe(true);
19
- });
20
- });
21
- (0, vitest_1.describe)('RPC Client', () => {
22
- (0, vitest_1.it)('should construct correct URLs and methods', async () => {
23
- // We mock fetch globally
24
- const originalFetch = global.fetch;
25
- global.fetch = async (url, options) => {
26
- return new Response(JSON.stringify({ url, method: options?.method }), {
27
- status: 200,
28
- headers: { 'Content-Type': 'application/json' },
29
- });
30
- };
31
- try {
32
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
- const client = (0, client_1.hc)('http://localhost:3000');
34
- const res1 = await client.api.users[':id'].$get({ param: { id: '123' } });
35
- const data1 = await res1.json();
36
- (0, vitest_1.expect)(data1.url).toBe('http://localhost:3000/api/users/123');
37
- (0, vitest_1.expect)(data1.method).toBe('GET');
38
- const res2 = await client.auth.login.$post({ json: { username: 'test' } });
39
- const data2 = await res2.json();
40
- (0, vitest_1.expect)(data2.url).toBe('http://localhost:3000/auth/login');
41
- (0, vitest_1.expect)(data2.method).toBe('POST');
42
- }
43
- finally {
44
- global.fetch = originalFetch;
45
- }
46
- });
47
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,92 +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)('Request Fusion Engine', () => {
6
- let app;
7
- (0, vitest_1.afterEach)(async () => {
8
- if (app)
9
- await app.close();
10
- });
11
- (0, vitest_1.it)('should coalesce simultaneous requests to the same endpoint', async () => {
12
- app = new server_1.QHTTPX({ enableRequestFusion: true });
13
- let executionCount = 0;
14
- // Simulate a slow handler
15
- app.get('/slow', async (ctx) => {
16
- executionCount++;
17
- await new Promise(resolve => setTimeout(resolve, 300));
18
- ctx.json({ count: executionCount });
19
- });
20
- const { port } = await app.listen(0);
21
- const url = `http://localhost:${port}/slow`;
22
- // Fire 3 requests simultaneously
23
- const p1 = fetch(url).then(r => r.json());
24
- const p2 = fetch(url).then(r => r.json());
25
- const p3 = fetch(url).then(r => r.json());
26
- const results = await Promise.all([p1, p2, p3]);
27
- // All should get the same result
28
- (0, vitest_1.expect)(results[0]).toEqual({ count: 1 });
29
- (0, vitest_1.expect)(results[1]).toEqual({ count: 1 });
30
- (0, vitest_1.expect)(results[2]).toEqual({ count: 1 });
31
- // Handler should have run only once
32
- (0, vitest_1.expect)(executionCount).toBe(1);
33
- });
34
- (0, vitest_1.it)('should NOT coalesce requests with different query params', async () => {
35
- app = new server_1.QHTTPX({ enableRequestFusion: true });
36
- let executionCount = 0;
37
- app.get('/echo', async (ctx) => {
38
- executionCount++;
39
- await new Promise(resolve => setTimeout(resolve, 20));
40
- ctx.json({ q: ctx.query.q, count: executionCount });
41
- });
42
- const { port } = await app.listen(0);
43
- const p1 = fetch(`http://localhost:${port}/echo?q=a`).then(r => r.json());
44
- const p2 = fetch(`http://localhost:${port}/echo?q=b`).then(r => r.json());
45
- const results = await Promise.all([p1, p2]);
46
- (0, vitest_1.expect)(results[0].q).toBe('a');
47
- (0, vitest_1.expect)(results[1].q).toBe('b');
48
- // Should run twice because keys are different
49
- (0, vitest_1.expect)(executionCount).toBe(2);
50
- });
51
- (0, vitest_1.it)('should use cache window to coalesce burst traffic', async () => {
52
- // 50ms window
53
- app = new server_1.QHTTPX({
54
- enableRequestFusion: { windowMs: 50 }
55
- });
56
- let executionCount = 0;
57
- app.get('/burst', async (ctx) => {
58
- executionCount++;
59
- // Fast handler
60
- ctx.json({ count: executionCount });
61
- });
62
- const { port } = await app.listen(0);
63
- const url = `http://localhost:${port}/burst`;
64
- // Request 1
65
- const r1 = await fetch(url).then(r => r.json());
66
- (0, vitest_1.expect)(r1.count).toBe(1);
67
- // Request 2 (immediate, within window)
68
- const r2 = await fetch(url).then(r => r.json());
69
- (0, vitest_1.expect)(r2.count).toBe(1); // Should be cached
70
- // Request 3 (wait 100ms, outside window)
71
- await new Promise(resolve => setTimeout(resolve, 100));
72
- const r3 = await fetch(url).then(r => r.json());
73
- (0, vitest_1.expect)(r3.count).toBe(2); // New execution
74
- });
75
- (0, vitest_1.it)('should respect vary headers (Authorization)', async () => {
76
- app = new server_1.QHTTPX({ enableRequestFusion: true });
77
- let executionCount = 0;
78
- app.get('/auth', async (ctx) => {
79
- executionCount++;
80
- await new Promise(resolve => setTimeout(resolve, 20));
81
- ctx.json({ user: ctx.req.headers['authorization'], count: executionCount });
82
- });
83
- const { port } = await app.listen(0);
84
- const url = `http://localhost:${port}/auth`;
85
- const p1 = fetch(url, { headers: { 'Authorization': 'UserA' } }).then(r => r.json());
86
- const p2 = fetch(url, { headers: { 'Authorization': 'UserB' } }).then(r => r.json());
87
- const results = await Promise.all([p1, p2]);
88
- (0, vitest_1.expect)(results[0].user).toBe('UserA');
89
- (0, vitest_1.expect)(results[1].user).toBe('UserB');
90
- (0, vitest_1.expect)(executionCount).toBe(2);
91
- });
92
- });
@@ -1 +0,0 @@
1
- export {};