qhttpx 1.8.12 → 1.9.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 (206) hide show
  1. package/package.json +26 -4
  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,131 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RadixTree = void 0;
4
- class Node {
5
- constructor() {
6
- // Map segment -> Node
7
- this.children = new Map();
8
- // Parameter child node (only one allowed per level for simplicity)
9
- this.paramChild = null;
10
- this.paramName = null;
11
- // Data if this node is a route end
12
- this.data = null;
13
- // Optimization: Pre-allocated match result for static matches
14
- this.staticMatch = null;
15
- }
16
- }
17
- class RadixTree {
18
- constructor() {
19
- this.root = new Node();
20
- }
21
- insert(segments, handler, priority) {
22
- let node = this.root;
23
- for (const segment of segments) {
24
- if (segment.startsWith(':')) {
25
- const paramName = segment.slice(1);
26
- if (!node.paramChild) {
27
- node.paramChild = new Node();
28
- node.paramChild.paramName = paramName;
29
- }
30
- else if (node.paramChild.paramName !== paramName) {
31
- throw new Error(`Cannot have two different parameter names at the same level: "${node.paramChild.paramName}" and "${paramName}"`);
32
- }
33
- node = node.paramChild;
34
- }
35
- else {
36
- if (!node.children.has(segment)) {
37
- node.children.set(segment, new Node());
38
- }
39
- node = node.children.get(segment);
40
- }
41
- }
42
- node.data = { handler, priority };
43
- node.staticMatch = { handler, priority, params: {} };
44
- }
45
- lookup(segments) {
46
- return this.find(this.root, segments, 0);
47
- }
48
- lookupPath(path) {
49
- if (path === '/' || path === '') {
50
- if (this.root.staticMatch) {
51
- return this.root.staticMatch;
52
- }
53
- return null;
54
- }
55
- const start = path.charCodeAt(0) === 47 ? 1 : 0;
56
- return this.findPath(this.root, path, start);
57
- }
58
- findPath(node, path, start) {
59
- // Handle trailing slash or end of path
60
- if (start >= path.length) {
61
- if (node.staticMatch) {
62
- return node.staticMatch;
63
- }
64
- return null;
65
- }
66
- let end = path.indexOf('/', start);
67
- if (end === -1) {
68
- end = path.length;
69
- }
70
- const segment = path.substring(start, end);
71
- const nextStart = end + 1;
72
- // Skip empty segments (e.g. //) to match normalize behavior
73
- if (segment.length === 0) {
74
- return this.findPath(node, path, nextStart);
75
- }
76
- // 1. Try exact match
77
- const child = node.children.get(segment);
78
- if (child) {
79
- const result = this.findPath(child, path, nextStart);
80
- if (result)
81
- return result;
82
- }
83
- // 2. Try param match
84
- if (node.paramChild) {
85
- const result = this.findPath(node.paramChild, path, nextStart);
86
- if (result) {
87
- // Clone params to avoid modifying shared staticMatch
88
- const newParams = { ...result.params };
89
- newParams[node.paramChild.paramName] = segment;
90
- return {
91
- handler: result.handler,
92
- priority: result.priority,
93
- params: newParams
94
- };
95
- }
96
- }
97
- return null;
98
- }
99
- find(node, segments, index) {
100
- if (index === segments.length) {
101
- if (node.data) {
102
- return {
103
- handler: node.data.handler,
104
- priority: node.data.priority,
105
- params: {},
106
- };
107
- }
108
- return null;
109
- }
110
- const segment = segments[index];
111
- // 1. Try exact match
112
- const child = node.children.get(segment);
113
- if (child) {
114
- const result = this.find(child, segments, index + 1);
115
- if (result) {
116
- return result;
117
- }
118
- }
119
- // 2. Try param match
120
- if (node.paramChild) {
121
- const result = this.find(node.paramChild, segments, index + 1);
122
- if (result) {
123
- // If match found down this path, add current param to it
124
- result.params[node.paramChild.paramName] = segment;
125
- return result;
126
- }
127
- }
128
- return null;
129
- }
130
- }
131
- exports.RadixTree = RadixTree;
@@ -1,34 +0,0 @@
1
- import { HTTPMethod, QHTTPXHandler, RouteOptions, RoutePriority } from '../core/types';
2
- import { RouteSchema } from '../validation/types';
3
- type RouteDefinition = {
4
- path: string;
5
- segments: string[];
6
- handler: QHTTPXHandler;
7
- priority: RoutePriority;
8
- schema?: RouteSchema | Record<string, unknown>;
9
- };
10
- export type RouteMatch = {
11
- handler: QHTTPXHandler;
12
- params: Record<string, string>;
13
- priority: RoutePriority;
14
- };
15
- export declare class Router {
16
- private readonly methodBuckets;
17
- private readonly radixTrees;
18
- private readonly staticRoutes;
19
- private isFrozen;
20
- register(method: HTTPMethod, path: string, handler: QHTTPXHandler, options?: RouteOptions & {
21
- schema?: RouteSchema | Record<string, unknown>;
22
- }): void;
23
- getRoutes(): Map<HTTPMethod, RouteDefinition[]>;
24
- match(method: HTTPMethod, path: string): RouteMatch | undefined;
25
- getAllowedMethods(path: string): HTTPMethod[];
26
- /**
27
- * Freeze the router after server starts.
28
- * Prevents further route registration and builds derived structures for optimized matching.
29
- */
30
- freeze(): void;
31
- isFrozenRouter(): boolean;
32
- private normalize;
33
- }
34
- export {};
@@ -1,186 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Router = void 0;
4
- const radix_tree_1 = require("./radix-tree");
5
- const types_1 = require("../core/types");
6
- class Router {
7
- constructor() {
8
- // Per-method route buckets
9
- this.methodBuckets = new Map([
10
- ['GET', []],
11
- ['POST', []],
12
- ['PUT', []],
13
- ['DELETE', []],
14
- ['PATCH', []],
15
- ['HEAD', []],
16
- ['OPTIONS', []],
17
- ]);
18
- // Derived structures (built at freeze time)
19
- this.radixTrees = new Map();
20
- // Fast lookup for static routes (no params)
21
- this.staticRoutes = new Map([
22
- ['GET', new Map()],
23
- ['POST', new Map()],
24
- ['PUT', new Map()],
25
- ['DELETE', new Map()],
26
- ['PATCH', new Map()],
27
- ['HEAD', new Map()],
28
- ['OPTIONS', new Map()],
29
- ]);
30
- // Freeze state
31
- this.isFrozen = false;
32
- }
33
- register(method, path, handler, options) {
34
- if (this.isFrozen) {
35
- console.warn(`Router is frozen. Late route registration (${method} ${path}) may not be optimized.`);
36
- }
37
- const segments = this.normalize(path);
38
- const bucket = this.methodBuckets.get(method);
39
- if (bucket) {
40
- bucket.push({
41
- path,
42
- segments,
43
- handler,
44
- priority: options?.priority ?? types_1.RoutePriority.STANDARD,
45
- schema: options?.schema,
46
- });
47
- }
48
- }
49
- getRoutes() {
50
- return this.methodBuckets;
51
- }
52
- match(method, path) {
53
- // Fast path for frozen router
54
- if (this.isFrozen) {
55
- // 1. Try static match (O(1))
56
- const staticMap = this.staticRoutes.get(method);
57
- if (staticMap) {
58
- const match = staticMap.get(path);
59
- if (match) {
60
- return match;
61
- }
62
- }
63
- // 2. Try radix tree match
64
- const tree = this.radixTrees.get(method);
65
- if (tree) {
66
- const match = tree.lookupPath(path);
67
- if (match) {
68
- return match;
69
- }
70
- }
71
- return undefined;
72
- }
73
- // Slow path for unfrozen router (legacy behavior)
74
- const segments = this.normalize(path);
75
- const bucket = this.methodBuckets.get(method);
76
- if (!bucket || bucket.length === 0) {
77
- return undefined;
78
- }
79
- // Try to match against routes
80
- for (const route of bucket) {
81
- if (route.segments.length !== segments.length) {
82
- continue;
83
- }
84
- const params = {};
85
- let matched = true;
86
- for (let i = 0; i < route.segments.length; i += 1) {
87
- const pattern = route.segments[i];
88
- const value = segments[i];
89
- if (pattern.startsWith(':')) {
90
- const key = pattern.slice(1);
91
- params[key] = value;
92
- }
93
- else if (pattern !== value) {
94
- matched = false;
95
- break;
96
- }
97
- }
98
- if (matched) {
99
- return {
100
- handler: route.handler,
101
- params,
102
- priority: route.priority,
103
- };
104
- }
105
- }
106
- return undefined;
107
- }
108
- getAllowedMethods(path) {
109
- const segments = this.normalize(path);
110
- const methods = [];
111
- for (const [method, routes] of this.methodBuckets.entries()) {
112
- for (const route of routes) {
113
- if (route.segments.length !== segments.length) {
114
- continue;
115
- }
116
- let matched = true;
117
- for (let i = 0; i < route.segments.length; i += 1) {
118
- const pattern = route.segments[i];
119
- const value = segments[i];
120
- if (pattern.startsWith(':')) {
121
- continue;
122
- }
123
- if (pattern !== value) {
124
- matched = false;
125
- break;
126
- }
127
- }
128
- if (matched) {
129
- methods.push(method);
130
- break;
131
- }
132
- }
133
- }
134
- return methods;
135
- }
136
- /**
137
- * Freeze the router after server starts.
138
- * Prevents further route registration and builds derived structures for optimized matching.
139
- */
140
- freeze() {
141
- if (this.isFrozen) {
142
- return;
143
- }
144
- this.isFrozen = true;
145
- // Build derived structures for faster matching
146
- for (const [method, routes] of this.methodBuckets.entries()) {
147
- const tree = new radix_tree_1.RadixTree();
148
- const staticMap = this.staticRoutes.get(method);
149
- for (const route of routes) {
150
- tree.insert(route.segments, route.handler, route.priority);
151
- // Check if route is static (no params)
152
- let isStatic = true;
153
- for (const segment of route.segments) {
154
- if (segment.startsWith(':')) {
155
- isStatic = false;
156
- break;
157
- }
158
- }
159
- if (isStatic) {
160
- // Optimization: Pre-allocate static match result
161
- // Note: we use route.path directly as key
162
- staticMap.set(route.path, {
163
- handler: route.handler,
164
- params: {},
165
- priority: route.priority,
166
- });
167
- // Also handle trailing slash or no trailing slash?
168
- // For strict matching, we use exact path.
169
- // QHTTPX seems to normalize, so /json/ and /json might be different?
170
- // route.path comes from user.
171
- }
172
- }
173
- this.radixTrees.set(method, tree);
174
- }
175
- }
176
- isFrozenRouter() {
177
- return this.isFrozen;
178
- }
179
- normalize(path) {
180
- if (!path || path === '/') {
181
- return [];
182
- }
183
- return path.split('/').filter((segment) => segment.length > 0);
184
- }
185
- }
186
- exports.Router = Router;
@@ -1,25 +0,0 @@
1
- import { QHTTPX } from '../core/server';
2
- import { HTTPMethod } from '../core/types';
3
- export declare class TestClient {
4
- private app;
5
- private server;
6
- private baseURL;
7
- constructor(app: QHTTPX);
8
- /**
9
- * Starts the server on a random port.
10
- * Automatically called by request methods if not started.
11
- */
12
- start(): Promise<void>;
13
- stop(): Promise<void>;
14
- request(method: HTTPMethod, path: string, options?: {
15
- headers?: Record<string, string>;
16
- body?: any;
17
- query?: Record<string, string | number | boolean>;
18
- }): Promise<Response>;
19
- get(path: string, options?: Omit<Parameters<TestClient['request']>[2], 'body'>): Promise<Response>;
20
- post(path: string, body?: any, options?: Omit<Parameters<TestClient['request']>[2], 'body'>): Promise<Response>;
21
- put(path: string, body?: any, options?: Omit<Parameters<TestClient['request']>[2], 'body'>): Promise<Response>;
22
- delete(path: string, options?: Omit<Parameters<TestClient['request']>[2], 'body'>): Promise<Response>;
23
- patch(path: string, body?: any, options?: Omit<Parameters<TestClient['request']>[2], 'body'>): Promise<Response>;
24
- }
25
- export declare function createTestClient(app: QHTTPX): TestClient;
@@ -1,84 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TestClient = void 0;
4
- exports.createTestClient = createTestClient;
5
- class TestClient {
6
- constructor(app) {
7
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
- this.server = null;
9
- this.baseURL = '';
10
- this.app = app;
11
- }
12
- /**
13
- * Starts the server on a random port.
14
- * Automatically called by request methods if not started.
15
- */
16
- async start() {
17
- if (this.server)
18
- return;
19
- const { port } = await this.app.listen(0);
20
- this.server = this.app.serverInstance;
21
- this.baseURL = `http://127.0.0.1:${port}`;
22
- }
23
- async stop() {
24
- if (this.server) {
25
- await this.app.close();
26
- this.server = null;
27
- }
28
- }
29
- async request(method, path, options = {}) {
30
- if (!this.server) {
31
- await this.start();
32
- }
33
- const url = new URL(path, this.baseURL);
34
- if (options.query) {
35
- Object.entries(options.query).forEach(([k, v]) => {
36
- url.searchParams.append(k, String(v));
37
- });
38
- }
39
- const headers = options.headers || {};
40
- let bodyPayload;
41
- if (options.body) {
42
- if (typeof options.body === 'object' &&
43
- !(options.body instanceof Uint8Array) &&
44
- !(options.body instanceof ArrayBuffer) &&
45
- !(options.body instanceof FormData) &&
46
- !(options.body instanceof URLSearchParams)) {
47
- bodyPayload = JSON.stringify(options.body);
48
- if (!headers['content-type']) {
49
- headers['content-type'] = 'application/json';
50
- }
51
- }
52
- else {
53
- bodyPayload = options.body;
54
- }
55
- }
56
- return fetch(url, {
57
- method,
58
- headers,
59
- body: bodyPayload,
60
- });
61
- }
62
- get(path, options) {
63
- return this.request('GET', path, options);
64
- }
65
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
66
- post(path, body, options) {
67
- return this.request('POST', path, { ...options, body });
68
- }
69
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
70
- put(path, body, options) {
71
- return this.request('PUT', path, { ...options, body });
72
- }
73
- delete(path, options) {
74
- return this.request('DELETE', path, options);
75
- }
76
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
77
- patch(path, body, options) {
78
- return this.request('PATCH', path, { ...options, body });
79
- }
80
- }
81
- exports.TestClient = TestClient;
82
- function createTestClient(app) {
83
- return new TestClient(app);
84
- }
@@ -1,3 +0,0 @@
1
- import { CookieOptions } from '../core/types';
2
- export declare function parseCookies(header: string | undefined): Record<string, string>;
3
- export declare function serializeCookie(name: string, value: string, options?: CookieOptions): string;
@@ -1,59 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseCookies = parseCookies;
4
- exports.serializeCookie = serializeCookie;
5
- function parseCookies(header) {
6
- const list = {};
7
- if (!header) {
8
- return list;
9
- }
10
- header.split(';').forEach((cookie) => {
11
- const parts = cookie.split('=');
12
- const name = parts.shift()?.trim();
13
- if (name) {
14
- const value = parts.join('=');
15
- list[name] = decodeURIComponent(value);
16
- }
17
- });
18
- return list;
19
- }
20
- function serializeCookie(name, value, options = {}) {
21
- let str = `${name}=${encodeURIComponent(value)}`;
22
- if (options.maxAge) {
23
- str += `; Max-Age=${Math.floor(options.maxAge)}`;
24
- }
25
- if (options.domain) {
26
- str += `; Domain=${options.domain}`;
27
- }
28
- if (options.path) {
29
- str += `; Path=${options.path}`;
30
- }
31
- else {
32
- str += '; Path=/';
33
- }
34
- if (options.expires) {
35
- str += `; Expires=${options.expires.toUTCString()}`;
36
- }
37
- if (options.httpOnly) {
38
- str += '; HttpOnly';
39
- }
40
- if (options.secure) {
41
- str += '; Secure';
42
- }
43
- if (options.sameSite) {
44
- switch (options.sameSite) {
45
- case 'lax':
46
- str += '; SameSite=Lax';
47
- break;
48
- case 'strict':
49
- str += '; SameSite=Strict';
50
- break;
51
- case 'none':
52
- str += '; SameSite=None';
53
- break;
54
- default:
55
- break;
56
- }
57
- }
58
- return str;
59
- }
@@ -1,12 +0,0 @@
1
- import { QHTTPXContext, QHTTPXMiddleware } from '../core/types';
2
- export type LogEntry = {
3
- method: string;
4
- path: string;
5
- status: number;
6
- durationMs: number;
7
- requestId?: string;
8
- };
9
- export type LoggerOptions = {
10
- sink?: (entry: LogEntry, ctx: QHTTPXContext) => void;
11
- };
12
- export declare function createLoggerMiddleware(options?: LoggerOptions): QHTTPXMiddleware;
@@ -1,45 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createLoggerMiddleware = createLoggerMiddleware;
4
- function createLoggerMiddleware(options = {}) {
5
- const sink = options.sink ??
6
- ((entry) => {
7
- const status = entry.status;
8
- let color = '\x1b[37m';
9
- if (status >= 200 && status < 300) {
10
- color = '\x1b[32m';
11
- }
12
- else if (status === 404) {
13
- color = '\x1b[33m';
14
- }
15
- else if (status >= 500) {
16
- color = '\x1b[34m';
17
- }
18
- else if (status >= 400) {
19
- color = '\x1b[35m';
20
- }
21
- const reset = '\x1b[0m';
22
- const prefix = entry.requestId ? `${entry.requestId} ` : '';
23
- const line = `${prefix}${entry.method} ${entry.path} ${status} ${entry.durationMs}ms`;
24
- console.log(`${color}${line}${reset}`);
25
- });
26
- return async (ctx, next) => {
27
- const start = ctx.requestStart ?? Date.now();
28
- try {
29
- await next();
30
- }
31
- finally {
32
- const durationMs = Math.max(1, Date.now() - start);
33
- const method = ctx.req.method || 'GET';
34
- const path = ctx.url.pathname;
35
- const status = ctx.res.statusCode || 200;
36
- sink({
37
- method,
38
- path,
39
- status,
40
- durationMs,
41
- requestId: ctx.requestId,
42
- }, ctx);
43
- }
44
- };
45
- }
@@ -1,6 +0,0 @@
1
- import { QHTTPX } from '../core/server';
2
- export type SignalHandlerOptions = {
3
- signals?: NodeJS.Signals[];
4
- timeoutMs?: number;
5
- };
6
- export declare function attachSignalHandlers(app: QHTTPX, options?: SignalHandlerOptions): void;
@@ -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,6 +0,0 @@
1
- import { QHTTPXContext } from '../core/types';
2
- export interface SSEStream {
3
- send(data: unknown, event?: string, id?: string): void;
4
- close(): void;
5
- }
6
- export declare function createSSE(ctx: QHTTPXContext): SSEStream;
@@ -1,32 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createSSE = createSSE;
4
- function createSSE(ctx) {
5
- const res = ctx.res;
6
- // Disable auto-end so we can keep the connection open
7
- ctx.disableAutoEnd = true;
8
- // Only write headers if not already sent
9
- if (!res.headersSent) {
10
- res.setHeader('Content-Type', 'text/event-stream');
11
- res.setHeader('Cache-Control', 'no-cache');
12
- res.setHeader('Connection', 'keep-alive');
13
- res.setHeader('X-Accel-Buffering', 'no'); // For Nginx
14
- // Send initial ping/comment to flush headers and establish connection
15
- res.write(': connected\n\n');
16
- }
17
- const send = (data, event, id) => {
18
- if (id)
19
- res.write(`id: ${id}\n`);
20
- if (event)
21
- res.write(`event: ${event}\n`);
22
- const payload = typeof data === 'string' ? data : JSON.stringify(data);
23
- res.write(`data: ${payload}\n\n`);
24
- };
25
- const close = () => {
26
- res.end();
27
- };
28
- ctx.req.on('close', () => {
29
- // console.log('SSE client disconnected');
30
- });
31
- return { send, close };
32
- }
@@ -1,3 +0,0 @@
1
- export * from './types';
2
- export * from './simple';
3
- export * from './zod';