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,87 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DatabaseManager = void 0;
4
- class DatabaseManager {
5
- constructor(config) {
6
- this.config = config;
7
- this.connections = new Map();
8
- }
9
- /**
10
- * Manually register an already initialized adapter instance
11
- * @param name The connection name
12
- * @param adapter The initialized adapter instance
13
- */
14
- registerConnection(name, adapter) {
15
- this.connections.set(name, adapter);
16
- }
17
- /**
18
- * Register a new database adapter type
19
- * @param type The type identifier (e.g., 'postgres', 'mysql', 'mongo')
20
- * @param adapter The adapter class
21
- */
22
- static registerAdapter(type, adapter) {
23
- DatabaseManager.adapterRegistry.set(type, adapter);
24
- }
25
- /**
26
- * Connect to a specific database or the default one
27
- * @param name Connection name from config
28
- */
29
- async connect(name) {
30
- const connectionName = name || this.config.default;
31
- if (!connectionName) {
32
- throw new Error('No connection name provided and no default connection configured.');
33
- }
34
- // Return existing connection if available and connected
35
- const existingConnection = this.connections.get(connectionName);
36
- if (existingConnection && existingConnection.isConnected()) {
37
- return existingConnection;
38
- }
39
- const dbConfig = this.config.connections[connectionName];
40
- if (!dbConfig) {
41
- throw new Error(`Connection configuration for '${connectionName}' not found.`);
42
- }
43
- const AdapterClass = DatabaseManager.adapterRegistry.get(dbConfig.type);
44
- if (!AdapterClass) {
45
- throw new Error(`No adapter registered for database type '${dbConfig.type}'.`);
46
- }
47
- const adapter = new AdapterClass(dbConfig);
48
- await adapter.connect();
49
- this.connections.set(connectionName, adapter);
50
- return adapter;
51
- }
52
- /**
53
- * Disconnect a specific connection or all connections
54
- * @param name Connection name (optional). If not provided, disconnects all.
55
- */
56
- async disconnect(name) {
57
- if (name) {
58
- const adapter = this.connections.get(name);
59
- if (adapter) {
60
- await adapter.disconnect();
61
- this.connections.delete(name);
62
- }
63
- }
64
- else {
65
- const promises = Array.from(this.connections.values()).map(adapter => adapter.disconnect());
66
- await Promise.all(promises);
67
- this.connections.clear();
68
- }
69
- }
70
- /**
71
- * Get an active connection
72
- * @param name Connection name
73
- */
74
- get(name) {
75
- const connectionName = name || this.config.default;
76
- if (!connectionName) {
77
- throw new Error('No connection name provided and no default connection configured.');
78
- }
79
- const adapter = this.connections.get(connectionName);
80
- if (!adapter) {
81
- throw new Error(`Connection '${connectionName}' is not active. Call connect() first.`);
82
- }
83
- return adapter;
84
- }
85
- }
86
- exports.DatabaseManager = DatabaseManager;
87
- DatabaseManager.adapterRegistry = new Map();
@@ -1,20 +0,0 @@
1
- export interface DatabaseConfig {
2
- type: string;
3
- url?: string;
4
- host?: string;
5
- port?: number;
6
- username?: string;
7
- password?: string;
8
- database?: string;
9
- options?: Record<string, any>;
10
- }
11
- export interface DatabaseAdapter {
12
- connect(): Promise<void>;
13
- disconnect(): Promise<void>;
14
- query<T = any>(query: string | object, params?: any[]): Promise<T>;
15
- isConnected(): boolean;
16
- }
17
- export interface DatabaseEngineOptions {
18
- default?: string;
19
- connections: Record<string, DatabaseConfig>;
20
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,50 +0,0 @@
1
- import { QHTTPX } from './core/server';
2
- import type { QHTTPXOptions } from './core/types';
3
- import { NativeAdapter } from './core/native-adapter';
4
- export { QHTTPX } from './core/server';
5
- export * from './core/types';
6
- export * from './core/errors';
7
- export * from './middleware/cors';
8
- export { createSecurityHeadersMiddleware, type SecurityHeadersOptions, createSecureDefaults, type SecureDefaultsOptions, } from './middleware/security';
9
- export * from './middleware/rate-limit';
10
- export * from './middleware/static';
11
- export * from './middleware/compression';
12
- export * from './core/stream';
13
- export * from './utils/logger';
14
- export { BufferPool, BufferPoolConfig } from './core/buffer-pool';
15
- export * from './testing';
16
- export * from './utils/signals';
17
- export * from './middleware/presets';
18
- export * from './utils/cookies';
19
- export * from './utils/sse';
20
- export { fastJsonStringify, getStringifier } from './core/serializer';
21
- export * from './database/types';
22
- export * from './database/manager';
23
- export * from './database/adapters/memory';
24
- export * from './views';
25
- export * from './validation';
26
- export * from './database/adapters/sqlite';
27
- export * from './database/adapters/postgres';
28
- export * from './database/adapters/mongo';
29
- export * from './core/fusion';
30
- export * from './validation/types';
31
- export * from './validation/simple';
32
- export * from './openapi/generator';
33
- export * from './client';
34
- export { NativeAdapter } from './core/native-adapter';
35
- export declare function createHttpApp(options?: QHTTPXOptions): QHTTPX;
36
- export declare function createNativeApp(options?: QHTTPXOptions): NativeAdapter;
37
- /**
38
- * Singleton instance for quick start
39
- * @example
40
- * import { app } from 'qhttpx';
41
- * app.get('/', ({ json }) => json({ hello: 'world' }));
42
- */
43
- export declare const app: QHTTPX;
44
- /**
45
- * Default export for simplified usage
46
- * @example
47
- * import QHTTPX from 'qhttpx';
48
- * const app = QHTTPX();
49
- */
50
- export default createHttpApp;
package/dist/src/index.js DELETED
@@ -1,91 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.app = exports.NativeAdapter = exports.getStringifier = exports.fastJsonStringify = exports.BufferPool = exports.createSecureDefaults = exports.createSecurityHeadersMiddleware = exports.QHTTPX = void 0;
18
- exports.createHttpApp = createHttpApp;
19
- exports.createNativeApp = createNativeApp;
20
- const server_1 = require("./core/server");
21
- const presets_1 = require("./middleware/presets");
22
- const native_adapter_1 = require("./core/native-adapter");
23
- var server_2 = require("./core/server");
24
- Object.defineProperty(exports, "QHTTPX", { enumerable: true, get: function () { return server_2.QHTTPX; } });
25
- __exportStar(require("./core/types"), exports);
26
- __exportStar(require("./core/errors"), exports);
27
- __exportStar(require("./middleware/cors"), exports);
28
- var security_1 = require("./middleware/security");
29
- Object.defineProperty(exports, "createSecurityHeadersMiddleware", { enumerable: true, get: function () { return security_1.createSecurityHeadersMiddleware; } });
30
- Object.defineProperty(exports, "createSecureDefaults", { enumerable: true, get: function () { return security_1.createSecureDefaults; } });
31
- __exportStar(require("./middleware/rate-limit"), exports);
32
- __exportStar(require("./middleware/static"), exports);
33
- __exportStar(require("./middleware/compression"), exports);
34
- __exportStar(require("./core/stream"), exports);
35
- __exportStar(require("./utils/logger"), exports);
36
- var buffer_pool_1 = require("./core/buffer-pool");
37
- Object.defineProperty(exports, "BufferPool", { enumerable: true, get: function () { return buffer_pool_1.BufferPool; } });
38
- __exportStar(require("./testing"), exports);
39
- __exportStar(require("./utils/signals"), exports);
40
- __exportStar(require("./middleware/presets"), exports);
41
- __exportStar(require("./utils/cookies"), exports);
42
- __exportStar(require("./utils/sse"), exports);
43
- var serializer_1 = require("./core/serializer");
44
- Object.defineProperty(exports, "fastJsonStringify", { enumerable: true, get: function () { return serializer_1.fastJsonStringify; } });
45
- Object.defineProperty(exports, "getStringifier", { enumerable: true, get: function () { return serializer_1.getStringifier; } });
46
- __exportStar(require("./database/types"), exports);
47
- __exportStar(require("./database/manager"), exports);
48
- __exportStar(require("./database/adapters/memory"), exports);
49
- __exportStar(require("./views"), exports);
50
- __exportStar(require("./validation"), exports);
51
- __exportStar(require("./database/adapters/sqlite"), exports);
52
- __exportStar(require("./database/adapters/postgres"), exports);
53
- __exportStar(require("./database/adapters/mongo"), exports);
54
- __exportStar(require("./core/fusion"), exports);
55
- __exportStar(require("./validation/types"), exports);
56
- __exportStar(require("./validation/simple"), exports);
57
- __exportStar(require("./openapi/generator"), exports);
58
- __exportStar(require("./client"), exports);
59
- var native_adapter_2 = require("./core/native-adapter");
60
- Object.defineProperty(exports, "NativeAdapter", { enumerable: true, get: function () { return native_adapter_2.NativeAdapter; } });
61
- function createHttpApp(options = {}) {
62
- const app = new server_1.QHTTPX(options);
63
- // Skip middleware in ultra mode for maximum performance
64
- if (options.performanceMode !== 'ultra') {
65
- const middlewares = (0, presets_1.createApiPreset)({
66
- rateLimit: options.rateLimit,
67
- cors: options.cors,
68
- compression: options.compression,
69
- });
70
- middlewares.forEach((mw) => app.use(mw));
71
- }
72
- return app;
73
- }
74
- function createNativeApp(options = {}) {
75
- const app = createHttpApp(options);
76
- return new native_adapter_1.NativeAdapter(app);
77
- }
78
- /**
79
- * Singleton instance for quick start
80
- * @example
81
- * import { app } from 'qhttpx';
82
- * app.get('/', ({ json }) => json({ hello: 'world' }));
83
- */
84
- exports.app = createHttpApp();
85
- /**
86
- * Default export for simplified usage
87
- * @example
88
- * import QHTTPX from 'qhttpx';
89
- * const app = QHTTPX();
90
- */
91
- exports.default = createHttpApp;
@@ -1,2 +0,0 @@
1
- import { QHTTPXMiddleware, CompressionOptions } from '../core/types';
2
- export declare function createCompressionMiddleware(options?: CompressionOptions): QHTTPXMiddleware;
@@ -1,133 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.createCompressionMiddleware = createCompressionMiddleware;
7
- const zlib_1 = __importDefault(require("zlib"));
8
- function createCompressionMiddleware(options = {}) {
9
- const threshold = options.threshold ?? 1024;
10
- const level = options.level ?? zlib_1.default.constants.Z_DEFAULT_COMPRESSION;
11
- return async (ctx, next) => {
12
- const req = ctx.req;
13
- const res = ctx.res;
14
- const acceptEncoding = req.headers['accept-encoding'] || '';
15
- let stream;
16
- let encoding = '';
17
- if (/\bbr\b/.test(acceptEncoding)) {
18
- stream = zlib_1.default.createBrotliCompress({
19
- params: {
20
- [zlib_1.default.constants.BROTLI_PARAM_QUALITY]: level,
21
- },
22
- });
23
- encoding = 'br';
24
- }
25
- else if (/\bgzip\b/.test(acceptEncoding)) {
26
- stream = zlib_1.default.createGzip({ level });
27
- encoding = 'gzip';
28
- }
29
- else if (/\bdeflate\b/.test(acceptEncoding)) {
30
- stream = zlib_1.default.createDeflate({ level });
31
- encoding = 'deflate';
32
- }
33
- if (!stream) {
34
- await next();
35
- return;
36
- }
37
- const originalWrite = res.write;
38
- const originalEnd = res.end;
39
- // const originalSetHeader = res.setHeader;
40
- // We need to defer compression decision until we know the content type/length
41
- // But since we are streaming, we might just start compressing if headers are sent?
42
- // Actually, we can hook into write/end.
43
- let headersSent = false;
44
- let compress = false;
45
- // Helper to check if we should compress based on content-type
46
- const shouldCompress = () => {
47
- const contentType = res.getHeader('content-type');
48
- if (!contentType)
49
- return true; // Assume yes if unknown? Or no? Usually text/json is compressed.
50
- const type = String(contentType).toLowerCase();
51
- if (type.includes('text/event-stream')) {
52
- return false;
53
- }
54
- return (type.includes('text') ||
55
- type.includes('json') ||
56
- type.includes('xml') ||
57
- type.includes('javascript') ||
58
- type.includes('svg'));
59
- };
60
- // Override write
61
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
- res.write = function (chunk, ...args) {
63
- if (!headersSent) {
64
- if (shouldCompress()) {
65
- compress = true;
66
- // Disable auto-end because we handle the stream asynchronously
67
- ctx.disableAutoEnd = true;
68
- res.setHeader('Content-Encoding', encoding);
69
- res.removeHeader('Content-Length');
70
- res.setHeader('Vary', 'Accept-Encoding');
71
- stream.on('data', (data) => {
72
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
73
- originalWrite.call(res, data);
74
- });
75
- stream.on('end', () => {
76
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
77
- originalEnd.call(res);
78
- });
79
- }
80
- else {
81
- compress = false;
82
- }
83
- headersSent = true;
84
- }
85
- if (compress && stream) {
86
- return stream.write(chunk, ...args);
87
- }
88
- else {
89
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
90
- return originalWrite.apply(res, [chunk, ...args]);
91
- }
92
- };
93
- // Override end
94
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
95
- res.end = function (chunk, ...args) {
96
- if (!headersSent) {
97
- const len = chunk ? Buffer.byteLength(chunk) : 0;
98
- if (shouldCompress() && len >= threshold) {
99
- compress = true;
100
- // Disable auto-end because we handle the stream asynchronously
101
- ctx.disableAutoEnd = true;
102
- res.setHeader('Content-Encoding', encoding);
103
- res.removeHeader('Content-Length');
104
- res.setHeader('Vary', 'Accept-Encoding');
105
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
106
- stream.on('data', (data) => originalWrite.call(res, data));
107
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
108
- stream.on('end', () => originalEnd.call(res));
109
- }
110
- else {
111
- compress = false;
112
- }
113
- headersSent = true;
114
- }
115
- if (compress && stream) {
116
- if (chunk)
117
- stream.write(chunk);
118
- stream.end();
119
- }
120
- else {
121
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
122
- return originalEnd.apply(res, [chunk, ...args]);
123
- }
124
- return res;
125
- };
126
- // Fix for the pipe issue:
127
- // If we set compress=true, we should pipe stream to res ONCE.
128
- // If we use { end: false }, we must manually end res.
129
- // If we use { end: true }, stream.end() will end res.
130
- // Let's refine the logic.
131
- await next();
132
- };
133
- }
@@ -1,2 +0,0 @@
1
- import { QHTTPXMiddleware, CorsOptions } from '../core/types';
2
- export declare function createCorsMiddleware(options?: CorsOptions): QHTTPXMiddleware;
@@ -1,66 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createCorsMiddleware = createCorsMiddleware;
4
- function resolveOrigin(origin, requestOrigin) {
5
- if (!origin) {
6
- return '*';
7
- }
8
- if (typeof origin === 'string') {
9
- return origin;
10
- }
11
- if (Array.isArray(origin)) {
12
- if (!requestOrigin) {
13
- return null;
14
- }
15
- if (origin.includes(requestOrigin)) {
16
- return requestOrigin;
17
- }
18
- return null;
19
- }
20
- return origin(requestOrigin);
21
- }
22
- function createCorsMiddleware(options = {}) {
23
- const methodsHeader = options.methods && options.methods.length > 0
24
- ? options.methods.join(', ')
25
- : 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS';
26
- const allowedHeadersHeader = options.allowedHeaders && options.allowedHeaders.length > 0
27
- ? options.allowedHeaders.join(', ')
28
- : undefined;
29
- const exposedHeadersHeader = options.exposedHeaders && options.exposedHeaders.length > 0
30
- ? options.exposedHeaders.join(', ')
31
- : undefined;
32
- const maxAgeHeader = typeof options.maxAgeSeconds === 'number'
33
- ? String(options.maxAgeSeconds)
34
- : undefined;
35
- const allowCredentials = options.credentials ?? false;
36
- return async (ctx, next) => {
37
- const requestOriginHeader = ctx.req.headers.origin;
38
- const resolvedOrigin = resolveOrigin(options.origin, requestOriginHeader);
39
- if (resolvedOrigin) {
40
- ctx.res.setHeader('access-control-allow-origin', resolvedOrigin);
41
- if (allowCredentials) {
42
- ctx.res.setHeader('access-control-allow-credentials', 'true');
43
- }
44
- if (exposedHeadersHeader) {
45
- ctx.res.setHeader('access-control-expose-headers', exposedHeadersHeader);
46
- }
47
- }
48
- if (ctx.req.method === 'OPTIONS') {
49
- ctx.res.statusCode = 204;
50
- ctx.res.setHeader('access-control-allow-methods', methodsHeader);
51
- const requestHeaders = typeof ctx.req.headers['access-control-request-headers'] === 'string'
52
- ? ctx.req.headers['access-control-request-headers']
53
- : undefined;
54
- const headersValue = allowedHeadersHeader || requestHeaders;
55
- if (headersValue) {
56
- ctx.res.setHeader('access-control-allow-headers', headersValue);
57
- }
58
- if (maxAgeHeader) {
59
- ctx.res.setHeader('access-control-max-age', maxAgeHeader);
60
- }
61
- ctx.res.end();
62
- return;
63
- }
64
- await next();
65
- };
66
- }
@@ -1,16 +0,0 @@
1
- import { QHTTPXMiddleware, RateLimitOptions, CorsOptions, CompressionOptions } from '../core/types';
2
- import { SecureDefaultsOptions } from './security';
3
- import { LoggerOptions } from '../utils/logger';
4
- import { StaticOptions } from './static';
5
- export type ApiPresetOptions = {
6
- security?: SecureDefaultsOptions;
7
- logging?: LoggerOptions | boolean;
8
- rateLimit?: RateLimitOptions;
9
- cors?: CorsOptions | boolean;
10
- compression?: CompressionOptions | boolean;
11
- };
12
- export declare function createApiPreset(options?: ApiPresetOptions): QHTTPXMiddleware[];
13
- export type StaticAppPresetOptions = ApiPresetOptions & {
14
- static: StaticOptions;
15
- };
16
- export declare function createStaticAppPreset(options: StaticAppPresetOptions): QHTTPXMiddleware[];
@@ -1,52 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createApiPreset = createApiPreset;
4
- exports.createStaticAppPreset = createStaticAppPreset;
5
- const security_1 = require("./security");
6
- const cors_1 = require("./cors");
7
- const compression_1 = require("./compression");
8
- const logger_1 = require("../utils/logger");
9
- const static_1 = require("./static");
10
- const rate_limit_1 = require("./rate-limit");
11
- function createApiPreset(options = {}) {
12
- const middlewares = [];
13
- // 1. CORS
14
- // Default to true (enabled) if not specified, to match createSecureDefaults behavior
15
- const corsOpts = options.cors ?? options.security?.cors ?? true;
16
- if (corsOpts !== false) {
17
- const opts = corsOpts === true ? {} : corsOpts;
18
- middlewares.push((0, cors_1.createCorsMiddleware)(opts));
19
- }
20
- // 2. Security Headers
21
- middlewares.push((0, security_1.createSecurityHeadersMiddleware)(options.security?.securityHeaders));
22
- // 3. Compression
23
- if (options.compression) {
24
- const opts = options.compression === true ? {} : options.compression;
25
- middlewares.push((0, compression_1.createCompressionMiddleware)(opts));
26
- }
27
- // 4. Logging
28
- if (options.logging !== false) {
29
- const loggerOptions = typeof options.logging === 'object' ? options.logging : {};
30
- middlewares.push((0, logger_1.createLoggerMiddleware)(loggerOptions));
31
- }
32
- // 5. Rate Limit
33
- if (options.rateLimit) {
34
- middlewares.push((0, rate_limit_1.rateLimit)(options.rateLimit));
35
- }
36
- return middlewares;
37
- }
38
- function createStaticAppPreset(options) {
39
- const middlewares = [];
40
- // 1. Security
41
- middlewares.push(...(0, security_1.createSecureDefaults)(options.security));
42
- // 2. Logging
43
- if (options.logging !== false) {
44
- const loggerOptions = typeof options.logging === 'object' ? options.logging : {};
45
- middlewares.push((0, logger_1.createLoggerMiddleware)(loggerOptions));
46
- }
47
- // 3. Static Files
48
- // We force fallthrough to true so API routes can handle non-static requests
49
- const staticOptions = { ...options.static, fallthrough: true };
50
- middlewares.push((0, static_1.createStaticMiddleware)(staticOptions));
51
- return middlewares;
52
- }
@@ -1,14 +0,0 @@
1
- import type { QHTTPXMiddleware, RateLimitOptions, RateLimitStore } from '../core/types';
2
- export declare class MemoryStore implements RateLimitStore {
3
- private hits;
4
- private interval?;
5
- constructor(clearPeriodMs?: number);
6
- increment(key: string, windowMs: number): Promise<{
7
- total: number;
8
- resetTime: number;
9
- }>;
10
- decrement(key: string): Promise<void>;
11
- reset(key: string): Promise<void>;
12
- private cleanup;
13
- }
14
- export declare const rateLimit: (options?: RateLimitOptions) => QHTTPXMiddleware;
@@ -1,83 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.rateLimit = exports.MemoryStore = void 0;
4
- class MemoryStore {
5
- constructor(clearPeriodMs = 60000) {
6
- this.hits = new Map();
7
- // Cleanup expired entries periodically
8
- if (clearPeriodMs > 0) {
9
- this.interval = setInterval(() => this.cleanup(), clearPeriodMs);
10
- this.interval.unref(); // Don't hold process open
11
- }
12
- }
13
- async increment(key, windowMs) {
14
- const now = Date.now();
15
- let record = this.hits.get(key);
16
- if (!record || now > record.resetTime) {
17
- record = { count: 1, resetTime: now + windowMs };
18
- this.hits.set(key, record);
19
- }
20
- else {
21
- record.count++;
22
- }
23
- return { total: record.count, resetTime: record.resetTime };
24
- }
25
- async decrement(key) {
26
- const record = this.hits.get(key);
27
- if (record && record.count > 0) {
28
- record.count--;
29
- }
30
- }
31
- async reset(key) {
32
- this.hits.delete(key);
33
- }
34
- cleanup() {
35
- const now = Date.now();
36
- for (const [key, record] of this.hits.entries()) {
37
- if (now > record.resetTime) {
38
- this.hits.delete(key);
39
- }
40
- }
41
- }
42
- }
43
- exports.MemoryStore = MemoryStore;
44
- const rateLimit = (options = {}) => {
45
- const windowMs = options.windowMs ?? 60000; // 1 minute default
46
- const max = options.max ?? 100; // 100 requests default
47
- const message = options.message ?? 'Too many requests, please try again later.';
48
- const statusCode = options.statusCode ?? 429;
49
- const headers = options.headers ?? true;
50
- const store = options.store ?? new MemoryStore();
51
- const keyGenerator = options.keyGenerator ?? ((ctx) => {
52
- if (options.trustProxy) {
53
- const forwarded = ctx.req.headers['x-forwarded-for'];
54
- if (forwarded) {
55
- return Array.isArray(forwarded) ? forwarded[0] : forwarded.split(',')[0].trim();
56
- }
57
- }
58
- return ctx.req.socket.remoteAddress || 'unknown';
59
- });
60
- return async (ctx, next) => {
61
- if (options.skip?.(ctx)) {
62
- return next();
63
- }
64
- const key = keyGenerator(ctx);
65
- const { total, resetTime } = await store.increment(key, windowMs);
66
- const remaining = Math.max(0, max - total);
67
- const resetSeconds = Math.ceil((resetTime - Date.now()) / 1000);
68
- if (headers) {
69
- ctx.res.setHeader('X-RateLimit-Limit', max);
70
- ctx.res.setHeader('X-RateLimit-Remaining', remaining);
71
- ctx.res.setHeader('X-RateLimit-Reset', resetSeconds);
72
- }
73
- if (total > max) {
74
- if (headers) {
75
- ctx.res.setHeader('Retry-After', resetSeconds);
76
- }
77
- ctx.json(typeof message === 'string' ? { error: message } : message, statusCode);
78
- return;
79
- }
80
- await next();
81
- };
82
- };
83
- exports.rateLimit = rateLimit;
@@ -1,21 +0,0 @@
1
- import { QHTTPXContext, QHTTPXMiddleware, CorsOptions } from '../core/types';
2
- export type SecurityHeadersOptions = {
3
- contentSecurityPolicy?: string | null;
4
- referrerPolicy?: string | null;
5
- xFrameOptions?: 'DENY' | 'SAMEORIGIN' | null;
6
- xContentTypeOptions?: 'nosniff' | null;
7
- xXssProtection?: '0' | '1; mode=block' | null;
8
- strictTransportSecurity?: string | null;
9
- };
10
- export declare function createSecurityHeadersMiddleware(options?: SecurityHeadersOptions): QHTTPXMiddleware;
11
- export type SecureDefaultsOptions = {
12
- cors?: CorsOptions;
13
- securityHeaders?: SecurityHeadersOptions;
14
- };
15
- export declare function createSecureDefaults(options?: SecureDefaultsOptions): QHTTPXMiddleware[];
16
- export type RateLimitOptions = {
17
- maxRequests: number;
18
- windowMs: number;
19
- keyGenerator?: (ctx: QHTTPXContext) => string;
20
- };
21
- export declare function createRateLimitMiddleware(options: RateLimitOptions): QHTTPXMiddleware;