qhttpx 1.8.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 (197) hide show
  1. package/.eslintrc.json +22 -0
  2. package/.github/workflows/ci.yml +32 -0
  3. package/.github/workflows/npm-publish.yml +37 -0
  4. package/.github/workflows/release.yml +21 -0
  5. package/.prettierrc +7 -0
  6. package/CHANGELOG.md +145 -0
  7. package/LICENSE +21 -0
  8. package/README.md +343 -0
  9. package/dist/package.json +61 -0
  10. package/dist/src/benchmarks/compare-frameworks.js +119 -0
  11. package/dist/src/benchmarks/quantam-users.js +56 -0
  12. package/dist/src/benchmarks/simple-json.js +58 -0
  13. package/dist/src/benchmarks/ultra-mode.js +122 -0
  14. package/dist/src/cli/index.js +200 -0
  15. package/dist/src/client/index.js +72 -0
  16. package/dist/src/core/batch.js +97 -0
  17. package/dist/src/core/body-parser.js +121 -0
  18. package/dist/src/core/buffer-pool.js +70 -0
  19. package/dist/src/core/config.js +50 -0
  20. package/dist/src/core/fusion.js +183 -0
  21. package/dist/src/core/logger.js +49 -0
  22. package/dist/src/core/metrics.js +111 -0
  23. package/dist/src/core/resources.js +25 -0
  24. package/dist/src/core/scheduler.js +85 -0
  25. package/dist/src/core/scope.js +68 -0
  26. package/dist/src/core/serializer.js +44 -0
  27. package/dist/src/core/server.js +905 -0
  28. package/dist/src/core/stream.js +71 -0
  29. package/dist/src/core/tasks.js +87 -0
  30. package/dist/src/core/types.js +19 -0
  31. package/dist/src/core/websocket.js +86 -0
  32. package/dist/src/core/worker-queue.js +73 -0
  33. package/dist/src/database/adapters/memory.js +90 -0
  34. package/dist/src/database/adapters/mongo.js +141 -0
  35. package/dist/src/database/adapters/postgres.js +111 -0
  36. package/dist/src/database/adapters/sqlite.js +42 -0
  37. package/dist/src/database/coalescer.js +134 -0
  38. package/dist/src/database/manager.js +87 -0
  39. package/dist/src/database/types.js +2 -0
  40. package/dist/src/index.js +61 -0
  41. package/dist/src/middleware/compression.js +133 -0
  42. package/dist/src/middleware/cors.js +66 -0
  43. package/dist/src/middleware/presets.js +33 -0
  44. package/dist/src/middleware/rate-limit.js +77 -0
  45. package/dist/src/middleware/security.js +69 -0
  46. package/dist/src/middleware/static.js +191 -0
  47. package/dist/src/openapi/generator.js +149 -0
  48. package/dist/src/router/radix-router.js +89 -0
  49. package/dist/src/router/radix-tree.js +81 -0
  50. package/dist/src/router/router.js +146 -0
  51. package/dist/src/testing/index.js +84 -0
  52. package/dist/src/utils/cookies.js +59 -0
  53. package/dist/src/utils/logger.js +45 -0
  54. package/dist/src/utils/signals.js +31 -0
  55. package/dist/src/utils/sse.js +32 -0
  56. package/dist/src/validation/index.js +19 -0
  57. package/dist/src/validation/simple.js +102 -0
  58. package/dist/src/validation/types.js +12 -0
  59. package/dist/src/validation/zod.js +18 -0
  60. package/dist/src/views/index.js +17 -0
  61. package/dist/src/views/types.js +2 -0
  62. package/dist/tests/adapters.test.js +106 -0
  63. package/dist/tests/batch.test.js +117 -0
  64. package/dist/tests/body-parser.test.js +52 -0
  65. package/dist/tests/compression-sse.test.js +87 -0
  66. package/dist/tests/cookies.test.js +63 -0
  67. package/dist/tests/cors.test.js +55 -0
  68. package/dist/tests/database.test.js +80 -0
  69. package/dist/tests/dx.test.js +64 -0
  70. package/dist/tests/ecosystem.test.js +133 -0
  71. package/dist/tests/features.test.js +47 -0
  72. package/dist/tests/fusion.test.js +92 -0
  73. package/dist/tests/http-basic.test.js +124 -0
  74. package/dist/tests/logger.test.js +33 -0
  75. package/dist/tests/middleware.test.js +109 -0
  76. package/dist/tests/observability.test.js +59 -0
  77. package/dist/tests/openapi.test.js +64 -0
  78. package/dist/tests/plugin.test.js +65 -0
  79. package/dist/tests/plugins.test.js +71 -0
  80. package/dist/tests/rate-limit.test.js +77 -0
  81. package/dist/tests/resources.test.js +44 -0
  82. package/dist/tests/scheduler.test.js +46 -0
  83. package/dist/tests/schema-routes.test.js +77 -0
  84. package/dist/tests/security.test.js +83 -0
  85. package/dist/tests/server-db.test.js +72 -0
  86. package/dist/tests/smoke.test.js +10 -0
  87. package/dist/tests/sqlite-fusion.test.js +92 -0
  88. package/dist/tests/static.test.js +102 -0
  89. package/dist/tests/stream.test.js +44 -0
  90. package/dist/tests/task-metrics.test.js +53 -0
  91. package/dist/tests/tasks.test.js +62 -0
  92. package/dist/tests/testing.test.js +47 -0
  93. package/dist/tests/validation.test.js +107 -0
  94. package/dist/tests/websocket.test.js +146 -0
  95. package/dist/vitest.config.js +9 -0
  96. package/docs/AEGIS.md +76 -0
  97. package/docs/BENCHMARKS.md +36 -0
  98. package/docs/CAPABILITIES.md +70 -0
  99. package/docs/CLI.md +43 -0
  100. package/docs/DATABASE.md +142 -0
  101. package/docs/ECOSYSTEM.md +146 -0
  102. package/docs/NEXT_STEPS.md +99 -0
  103. package/docs/OPENAPI.md +99 -0
  104. package/docs/PLUGINS.md +59 -0
  105. package/docs/REAL_WORLD_EXAMPLES.md +109 -0
  106. package/docs/ROADMAP.md +366 -0
  107. package/docs/VALIDATION.md +136 -0
  108. package/eslint.config.cjs +26 -0
  109. package/examples/api-server.ts +254 -0
  110. package/package.json +61 -0
  111. package/src/benchmarks/compare-frameworks.ts +149 -0
  112. package/src/benchmarks/quantam-users.ts +70 -0
  113. package/src/benchmarks/simple-json.ts +71 -0
  114. package/src/benchmarks/ultra-mode.ts +159 -0
  115. package/src/cli/index.ts +214 -0
  116. package/src/client/index.ts +93 -0
  117. package/src/core/batch.ts +110 -0
  118. package/src/core/body-parser.ts +151 -0
  119. package/src/core/buffer-pool.ts +96 -0
  120. package/src/core/config.ts +60 -0
  121. package/src/core/fusion.ts +210 -0
  122. package/src/core/logger.ts +70 -0
  123. package/src/core/metrics.ts +166 -0
  124. package/src/core/resources.ts +38 -0
  125. package/src/core/scheduler.ts +126 -0
  126. package/src/core/scope.ts +87 -0
  127. package/src/core/serializer.ts +41 -0
  128. package/src/core/server.ts +1113 -0
  129. package/src/core/stream.ts +111 -0
  130. package/src/core/tasks.ts +138 -0
  131. package/src/core/types.ts +178 -0
  132. package/src/core/websocket.ts +112 -0
  133. package/src/core/worker-queue.ts +90 -0
  134. package/src/database/adapters/memory.ts +99 -0
  135. package/src/database/adapters/mongo.ts +116 -0
  136. package/src/database/adapters/postgres.ts +86 -0
  137. package/src/database/adapters/sqlite.ts +44 -0
  138. package/src/database/coalescer.ts +153 -0
  139. package/src/database/manager.ts +97 -0
  140. package/src/database/types.ts +24 -0
  141. package/src/index.ts +42 -0
  142. package/src/middleware/compression.ts +147 -0
  143. package/src/middleware/cors.ts +98 -0
  144. package/src/middleware/presets.ts +50 -0
  145. package/src/middleware/rate-limit.ts +106 -0
  146. package/src/middleware/security.ts +109 -0
  147. package/src/middleware/static.ts +216 -0
  148. package/src/openapi/generator.ts +167 -0
  149. package/src/router/radix-router.ts +119 -0
  150. package/src/router/radix-tree.ts +106 -0
  151. package/src/router/router.ts +190 -0
  152. package/src/testing/index.ts +104 -0
  153. package/src/utils/cookies.ts +67 -0
  154. package/src/utils/logger.ts +59 -0
  155. package/src/utils/signals.ts +45 -0
  156. package/src/utils/sse.ts +41 -0
  157. package/src/validation/index.ts +3 -0
  158. package/src/validation/simple.ts +93 -0
  159. package/src/validation/types.ts +38 -0
  160. package/src/validation/zod.ts +14 -0
  161. package/src/views/index.ts +1 -0
  162. package/src/views/types.ts +4 -0
  163. package/tests/adapters.test.ts +120 -0
  164. package/tests/batch.test.ts +139 -0
  165. package/tests/body-parser.test.ts +83 -0
  166. package/tests/compression-sse.test.ts +98 -0
  167. package/tests/cookies.test.ts +74 -0
  168. package/tests/cors.test.ts +79 -0
  169. package/tests/database.test.ts +90 -0
  170. package/tests/dx.test.ts +78 -0
  171. package/tests/ecosystem.test.ts +156 -0
  172. package/tests/features.test.ts +51 -0
  173. package/tests/fusion.test.ts +121 -0
  174. package/tests/http-basic.test.ts +161 -0
  175. package/tests/logger.test.ts +48 -0
  176. package/tests/middleware.test.ts +137 -0
  177. package/tests/observability.test.ts +91 -0
  178. package/tests/openapi.test.ts +74 -0
  179. package/tests/plugin.test.ts +85 -0
  180. package/tests/plugins.test.ts +93 -0
  181. package/tests/rate-limit.test.ts +97 -0
  182. package/tests/resources.test.ts +64 -0
  183. package/tests/scheduler.test.ts +71 -0
  184. package/tests/schema-routes.test.ts +89 -0
  185. package/tests/security.test.ts +128 -0
  186. package/tests/server-db.test.ts +72 -0
  187. package/tests/smoke.test.ts +9 -0
  188. package/tests/sqlite-fusion.test.ts +106 -0
  189. package/tests/static.test.ts +111 -0
  190. package/tests/stream.test.ts +58 -0
  191. package/tests/task-metrics.test.ts +78 -0
  192. package/tests/tasks.test.ts +90 -0
  193. package/tests/testing.test.ts +53 -0
  194. package/tests/validation.test.ts +126 -0
  195. package/tests/websocket.test.ts +132 -0
  196. package/tsconfig.json +16 -0
  197. package/vitest.config.ts +9 -0
@@ -0,0 +1,25 @@
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.calculateWorkerCount = calculateWorkerCount;
7
+ exports.isResourceOverloaded = isResourceOverloaded;
8
+ const os_1 = __importDefault(require("os"));
9
+ function calculateWorkerCount(setting) {
10
+ if (typeof setting === 'number') {
11
+ if (!Number.isFinite(setting) || setting <= 0) {
12
+ return 1;
13
+ }
14
+ return Math.floor(setting);
15
+ }
16
+ const cpuCount = os_1.default.cpus().length || 1;
17
+ return Math.max(1, cpuCount);
18
+ }
19
+ function isResourceOverloaded(sample, thresholds) {
20
+ if (thresholds.maxRssBytes !== undefined &&
21
+ sample.rssBytes > thresholds.maxRssBytes) {
22
+ return true;
23
+ }
24
+ return false;
25
+ }
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Scheduler = void 0;
4
+ const worker_queue_1 = require("./worker-queue");
5
+ const types_1 = require("./types");
6
+ class Scheduler {
7
+ constructor(options = {}) {
8
+ this.inFlight = 0;
9
+ this.nextWorkerIndex = 0;
10
+ const max = options.maxConcurrency ?? Infinity;
11
+ this.maxConcurrency = max > 0 ? max : Infinity;
12
+ // Initialize per-worker queues
13
+ this.workerCount = options.workers ?? 1;
14
+ this.perWorkerQueues = [];
15
+ for (let i = 0; i < this.workerCount; i += 1) {
16
+ this.perWorkerQueues.push(new worker_queue_1.WorkerQueue(1024));
17
+ }
18
+ }
19
+ getCurrentInFlight() {
20
+ return this.inFlight;
21
+ }
22
+ /**
23
+ * Get scheduler statistics (queued tasks per worker, etc.)
24
+ */
25
+ getStats() {
26
+ return {
27
+ inFlight: this.inFlight,
28
+ maxConcurrency: this.maxConcurrency,
29
+ workers: this.workerCount,
30
+ perWorkerStats: this.perWorkerQueues.map((q, i) => ({
31
+ workerId: i,
32
+ queued: q.getSize(),
33
+ })),
34
+ };
35
+ }
36
+ async run(task, options) {
37
+ const priority = options.priority ?? types_1.RoutePriority.STANDARD;
38
+ let threshold = this.maxConcurrency;
39
+ if (priority === types_1.RoutePriority.BEST_EFFORT) {
40
+ // Shed best-effort requests if we are above 80% capacity
41
+ threshold = Math.max(1, Math.floor(this.maxConcurrency * 0.8));
42
+ }
43
+ else if (priority === types_1.RoutePriority.STANDARD) {
44
+ // Shed standard requests if we are above 95% capacity
45
+ threshold = Math.max(1, Math.floor(this.maxConcurrency * 0.95));
46
+ }
47
+ // CRITICAL allows up to 100%
48
+ if (this.inFlight >= threshold) {
49
+ if (options.onOverloaded) {
50
+ options.onOverloaded();
51
+ }
52
+ return;
53
+ }
54
+ this.inFlight += 1;
55
+ let timeoutId;
56
+ try {
57
+ if (!options.timeoutMs || options.timeoutMs <= 0) {
58
+ const result = task();
59
+ if (result && typeof result.then === 'function') {
60
+ await result;
61
+ }
62
+ return;
63
+ }
64
+ const taskPromise = Promise.resolve(task()).then(() => 'ok');
65
+ const timeoutPromise = new Promise((resolve) => {
66
+ timeoutId = setTimeout(() => {
67
+ resolve('timeout');
68
+ }, options.timeoutMs);
69
+ });
70
+ const result = await Promise.race([taskPromise, timeoutPromise]);
71
+ if (result === 'timeout') {
72
+ if (options.onTimeout) {
73
+ options.onTimeout();
74
+ }
75
+ }
76
+ }
77
+ finally {
78
+ if (timeoutId) {
79
+ clearTimeout(timeoutId);
80
+ }
81
+ this.inFlight -= 1;
82
+ }
83
+ }
84
+ }
85
+ exports.Scheduler = Scheduler;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QHTTPXScope = void 0;
4
+ /**
5
+ * A Scope represents a prefixed or isolated context for plugins.
6
+ * It proxies methods to the main QHTTPX instance but handles prefixing.
7
+ */
8
+ class QHTTPXScope {
9
+ constructor(app, prefix = '') {
10
+ this.app = app;
11
+ this.prefix = prefix;
12
+ }
13
+ /**
14
+ * Registers a sub-plugin within this scope.
15
+ * Prefixes are concatenated (e.g. /v1 + /users = /v1/users).
16
+ */
17
+ async register(plugin, options) {
18
+ const newPrefix = this.joinPaths(this.prefix, options?.prefix || '');
19
+ const scope = new QHTTPXScope(this.app, newPrefix);
20
+ await plugin(scope, options);
21
+ }
22
+ use(middleware) {
23
+ // Middleware in scopes is currently global (TODO: Encapsulated middleware)
24
+ this.app.use(middleware);
25
+ }
26
+ get(path, handler) {
27
+ this.app._registerRoute('GET', this.joinPaths(this.prefix, path), handler);
28
+ }
29
+ post(path, handler) {
30
+ this.app._registerRoute('POST', this.joinPaths(this.prefix, path), handler);
31
+ }
32
+ put(path, handler) {
33
+ this.app._registerRoute('PUT', this.joinPaths(this.prefix, path), handler);
34
+ }
35
+ delete(path, handler) {
36
+ this.app._registerRoute('DELETE', this.joinPaths(this.prefix, path), handler);
37
+ }
38
+ patch(path, handler) {
39
+ this.app._registerRoute('PATCH', this.joinPaths(this.prefix, path), handler);
40
+ }
41
+ options(path, handler) {
42
+ this.app._registerRoute('OPTIONS', this.joinPaths(this.prefix, path), handler);
43
+ }
44
+ head(path, handler) {
45
+ this.app._registerRoute('HEAD', this.joinPaths(this.prefix, path), handler);
46
+ }
47
+ // Helper to access the main app if needed
48
+ getApp() {
49
+ return this.app;
50
+ }
51
+ joinPaths(head, tail) {
52
+ if (!head)
53
+ return tail;
54
+ if (!tail)
55
+ return head;
56
+ // Ensure clean slash joining
57
+ const headSlash = head.endsWith('/');
58
+ const tailSlash = tail.startsWith('/');
59
+ if (headSlash && tailSlash) {
60
+ return head + tail.slice(1);
61
+ }
62
+ if (!headSlash && !tailSlash) {
63
+ return head + '/' + tail;
64
+ }
65
+ return head + tail;
66
+ }
67
+ }
68
+ exports.QHTTPXScope = QHTTPXScope;
@@ -0,0 +1,44 @@
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.fastJsonStringify = fastJsonStringify;
7
+ exports.getStringifier = getStringifier;
8
+ const fast_json_stringify_1 = __importDefault(require("fast-json-stringify"));
9
+ // Cache of compiled stringifiers per schema
10
+ const stringifierCache = new Map();
11
+ // Default fast JSON stringifier for generic objects
12
+ const defaultStringifier = (0, fast_json_stringify_1.default)({
13
+ type: 'object',
14
+ additionalProperties: true,
15
+ });
16
+ /**
17
+ * Fast JSON serializer using fast-json-stringify
18
+ * For best performance, use schema-based stringifiers per route
19
+ */
20
+ function fastJsonStringify(value, schema) {
21
+ if (schema) {
22
+ const schemaKey = JSON.stringify(schema);
23
+ let stringifier = stringifierCache.get(schemaKey);
24
+ if (!stringifier) {
25
+ stringifier = (0, fast_json_stringify_1.default)(schema);
26
+ stringifierCache.set(schemaKey, stringifier);
27
+ }
28
+ return stringifier(value);
29
+ }
30
+ return defaultStringifier(value);
31
+ }
32
+ /**
33
+ * Get a pre-compiled stringifier for a specific schema
34
+ * Use this in route handlers for maximum performance
35
+ */
36
+ function getStringifier(schema) {
37
+ const schemaKey = JSON.stringify(schema);
38
+ let stringifier = stringifierCache.get(schemaKey);
39
+ if (!stringifier) {
40
+ stringifier = (0, fast_json_stringify_1.default)(schema);
41
+ stringifierCache.set(schemaKey, stringifier);
42
+ }
43
+ return stringifier;
44
+ }