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.
- package/package.json +26 -4
- package/prebuilds/darwin-arm64/qhttpx.node +0 -0
- package/prebuilds/linux-x64/qhttpx.node +0 -0
- package/prebuilds/win32-x64/qhttpx.node +0 -0
- package/src/native/index.ts +104 -24
- package/src/native/picohttpparser.h +5 -0
- package/src/native/server.cc +2 -0
- package/dist/examples/api-server.d.ts +0 -1
- package/dist/examples/api-server.js +0 -77
- package/dist/examples/basic.d.ts +0 -1
- package/dist/examples/basic.js +0 -10
- package/dist/examples/compression.d.ts +0 -1
- package/dist/examples/compression.js +0 -17
- package/dist/examples/cors.d.ts +0 -1
- package/dist/examples/cors.js +0 -19
- package/dist/examples/errors.d.ts +0 -1
- package/dist/examples/errors.js +0 -25
- package/dist/examples/file-upload.d.ts +0 -1
- package/dist/examples/file-upload.js +0 -24
- package/dist/examples/fusion.d.ts +0 -1
- package/dist/examples/fusion.js +0 -21
- package/dist/examples/rate-limiting.d.ts +0 -1
- package/dist/examples/rate-limiting.js +0 -17
- package/dist/examples/validation.d.ts +0 -1
- package/dist/examples/validation.js +0 -23
- package/dist/examples/websockets.d.ts +0 -1
- package/dist/examples/websockets.js +0 -20
- package/dist/package.json +0 -101
- package/dist/src/benchmarks/quantam-users.d.ts +0 -1
- package/dist/src/benchmarks/quantam-users.js +0 -56
- package/dist/src/benchmarks/simple-json.d.ts +0 -1
- package/dist/src/benchmarks/simple-json.js +0 -60
- package/dist/src/benchmarks/ultra-mode.d.ts +0 -1
- package/dist/src/benchmarks/ultra-mode.js +0 -94
- package/dist/src/cli/index.d.ts +0 -2
- package/dist/src/cli/index.js +0 -222
- package/dist/src/client/index.d.ts +0 -17
- package/dist/src/client/index.js +0 -72
- package/dist/src/core/batch.d.ts +0 -24
- package/dist/src/core/batch.js +0 -97
- package/dist/src/core/body-parser.d.ts +0 -15
- package/dist/src/core/body-parser.js +0 -121
- package/dist/src/core/buffer-pool.d.ts +0 -41
- package/dist/src/core/buffer-pool.js +0 -70
- package/dist/src/core/config.d.ts +0 -7
- package/dist/src/core/config.js +0 -50
- package/dist/src/core/errors.d.ts +0 -34
- package/dist/src/core/errors.js +0 -70
- package/dist/src/core/fusion.d.ts +0 -14
- package/dist/src/core/fusion.js +0 -183
- package/dist/src/core/logger.d.ts +0 -22
- package/dist/src/core/logger.js +0 -49
- package/dist/src/core/metrics.d.ts +0 -45
- package/dist/src/core/metrics.js +0 -111
- package/dist/src/core/native-adapter.d.ts +0 -11
- package/dist/src/core/native-adapter.js +0 -211
- package/dist/src/core/resources.d.ts +0 -9
- package/dist/src/core/resources.js +0 -25
- package/dist/src/core/scheduler.d.ts +0 -34
- package/dist/src/core/scheduler.js +0 -85
- package/dist/src/core/scope.d.ts +0 -26
- package/dist/src/core/scope.js +0 -68
- package/dist/src/core/serializer.d.ts +0 -10
- package/dist/src/core/serializer.js +0 -44
- package/dist/src/core/server.d.ts +0 -138
- package/dist/src/core/server.js +0 -1082
- package/dist/src/core/stream.d.ts +0 -15
- package/dist/src/core/stream.js +0 -71
- package/dist/src/core/tasks.d.ts +0 -29
- package/dist/src/core/tasks.js +0 -87
- package/dist/src/core/types.d.ts +0 -173
- package/dist/src/core/types.js +0 -19
- package/dist/src/core/websocket.d.ts +0 -25
- package/dist/src/core/websocket.js +0 -86
- package/dist/src/core/worker-queue.d.ts +0 -41
- package/dist/src/core/worker-queue.js +0 -73
- package/dist/src/database/adapters/memory.d.ts +0 -21
- package/dist/src/database/adapters/memory.js +0 -90
- package/dist/src/database/adapters/mongo.d.ts +0 -11
- package/dist/src/database/adapters/mongo.js +0 -141
- package/dist/src/database/adapters/postgres.d.ts +0 -10
- package/dist/src/database/adapters/postgres.js +0 -111
- package/dist/src/database/adapters/sqlite.d.ts +0 -10
- package/dist/src/database/adapters/sqlite.js +0 -42
- package/dist/src/database/coalescer.d.ts +0 -14
- package/dist/src/database/coalescer.js +0 -134
- package/dist/src/database/manager.d.ts +0 -35
- package/dist/src/database/manager.js +0 -87
- package/dist/src/database/types.d.ts +0 -20
- package/dist/src/database/types.js +0 -2
- package/dist/src/index.d.ts +0 -50
- package/dist/src/index.js +0 -91
- package/dist/src/middleware/compression.d.ts +0 -2
- package/dist/src/middleware/compression.js +0 -133
- package/dist/src/middleware/cors.d.ts +0 -2
- package/dist/src/middleware/cors.js +0 -66
- package/dist/src/middleware/presets.d.ts +0 -16
- package/dist/src/middleware/presets.js +0 -52
- package/dist/src/middleware/rate-limit.d.ts +0 -14
- package/dist/src/middleware/rate-limit.js +0 -83
- package/dist/src/middleware/security.d.ts +0 -21
- package/dist/src/middleware/security.js +0 -69
- package/dist/src/middleware/static.d.ts +0 -11
- package/dist/src/middleware/static.js +0 -191
- package/dist/src/native/index.d.ts +0 -29
- package/dist/src/native/index.js +0 -64
- package/dist/src/openapi/generator.d.ts +0 -19
- package/dist/src/openapi/generator.js +0 -149
- package/dist/src/router/radix-router.d.ts +0 -18
- package/dist/src/router/radix-router.js +0 -89
- package/dist/src/router/radix-tree.d.ts +0 -18
- package/dist/src/router/radix-tree.js +0 -131
- package/dist/src/router/router.d.ts +0 -34
- package/dist/src/router/router.js +0 -186
- package/dist/src/testing/index.d.ts +0 -25
- package/dist/src/testing/index.js +0 -84
- package/dist/src/utils/cookies.d.ts +0 -3
- package/dist/src/utils/cookies.js +0 -59
- package/dist/src/utils/logger.d.ts +0 -12
- package/dist/src/utils/logger.js +0 -45
- package/dist/src/utils/signals.d.ts +0 -6
- package/dist/src/utils/signals.js +0 -31
- package/dist/src/utils/sse.d.ts +0 -6
- package/dist/src/utils/sse.js +0 -32
- package/dist/src/validation/index.d.ts +0 -3
- package/dist/src/validation/index.js +0 -19
- package/dist/src/validation/simple.d.ts +0 -5
- package/dist/src/validation/simple.js +0 -102
- package/dist/src/validation/types.d.ts +0 -32
- package/dist/src/validation/types.js +0 -12
- package/dist/src/validation/zod.d.ts +0 -4
- package/dist/src/validation/zod.js +0 -18
- package/dist/src/views/index.d.ts +0 -1
- package/dist/src/views/index.js +0 -17
- package/dist/src/views/types.d.ts +0 -3
- package/dist/src/views/types.js +0 -2
- package/dist/tests/adapters.test.d.ts +0 -1
- package/dist/tests/adapters.test.js +0 -106
- package/dist/tests/batch.test.d.ts +0 -1
- package/dist/tests/batch.test.js +0 -117
- package/dist/tests/body-parser.test.d.ts +0 -1
- package/dist/tests/body-parser.test.js +0 -52
- package/dist/tests/compression-sse.test.d.ts +0 -1
- package/dist/tests/compression-sse.test.js +0 -87
- package/dist/tests/cookies.test.d.ts +0 -1
- package/dist/tests/cookies.test.js +0 -63
- package/dist/tests/cors.test.d.ts +0 -1
- package/dist/tests/cors.test.js +0 -55
- package/dist/tests/database.test.d.ts +0 -1
- package/dist/tests/database.test.js +0 -80
- package/dist/tests/dx.test.d.ts +0 -1
- package/dist/tests/dx.test.js +0 -114
- package/dist/tests/ecosystem.test.d.ts +0 -1
- package/dist/tests/ecosystem.test.js +0 -133
- package/dist/tests/features.test.d.ts +0 -1
- package/dist/tests/features.test.js +0 -47
- package/dist/tests/fusion.test.d.ts +0 -1
- package/dist/tests/fusion.test.js +0 -92
- package/dist/tests/http-basic.test.d.ts +0 -1
- package/dist/tests/http-basic.test.js +0 -124
- package/dist/tests/logger.test.d.ts +0 -1
- package/dist/tests/logger.test.js +0 -33
- package/dist/tests/middleware.test.d.ts +0 -1
- package/dist/tests/middleware.test.js +0 -109
- package/dist/tests/native-adapter.test.d.ts +0 -1
- package/dist/tests/native-adapter.test.js +0 -71
- package/dist/tests/observability.test.d.ts +0 -1
- package/dist/tests/observability.test.js +0 -59
- package/dist/tests/openapi.test.d.ts +0 -1
- package/dist/tests/openapi.test.js +0 -64
- package/dist/tests/plugin.test.d.ts +0 -1
- package/dist/tests/plugin.test.js +0 -65
- package/dist/tests/plugins.test.d.ts +0 -1
- package/dist/tests/plugins.test.js +0 -71
- package/dist/tests/rate-limit.test.d.ts +0 -1
- package/dist/tests/rate-limit.test.js +0 -77
- package/dist/tests/resources.test.d.ts +0 -1
- package/dist/tests/resources.test.js +0 -47
- package/dist/tests/scheduler.test.d.ts +0 -1
- package/dist/tests/scheduler.test.js +0 -46
- package/dist/tests/schema-routes.test.d.ts +0 -1
- package/dist/tests/schema-routes.test.js +0 -77
- package/dist/tests/security.test.d.ts +0 -1
- package/dist/tests/security.test.js +0 -83
- package/dist/tests/server-db.test.d.ts +0 -1
- package/dist/tests/server-db.test.js +0 -72
- package/dist/tests/smoke.test.d.ts +0 -1
- package/dist/tests/smoke.test.js +0 -10
- package/dist/tests/sqlite-fusion.test.d.ts +0 -1
- package/dist/tests/sqlite-fusion.test.js +0 -92
- package/dist/tests/static.test.d.ts +0 -1
- package/dist/tests/static.test.js +0 -102
- package/dist/tests/stream.test.d.ts +0 -1
- package/dist/tests/stream.test.js +0 -44
- package/dist/tests/task-metrics.test.d.ts +0 -1
- package/dist/tests/task-metrics.test.js +0 -53
- package/dist/tests/tasks.test.d.ts +0 -1
- package/dist/tests/tasks.test.js +0 -62
- package/dist/tests/testing.test.d.ts +0 -1
- package/dist/tests/testing.test.js +0 -47
- package/dist/tests/validation.test.d.ts +0 -1
- package/dist/tests/validation.test.js +0 -107
- package/dist/tests/websocket.test.d.ts +0 -1
- package/dist/tests/websocket.test.js +0 -146
- package/dist/vitest.config.d.ts +0 -2
- package/dist/vitest.config.js +0 -9
package/dist/src/core/batch.js
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BatchExecutor = void 0;
|
|
4
|
-
const coalescer_1 = require("../database/coalescer");
|
|
5
|
-
class BatchExecutor {
|
|
6
|
-
constructor(dbManager) {
|
|
7
|
-
this.ops = new Map();
|
|
8
|
-
this.coalescers = new Map();
|
|
9
|
-
this.dbManager = dbManager;
|
|
10
|
-
}
|
|
11
|
-
register(name, handler) {
|
|
12
|
-
this.ops.set(name, handler);
|
|
13
|
-
}
|
|
14
|
-
async handleBatch(ctx, batch) {
|
|
15
|
-
if (!Array.isArray(batch)) {
|
|
16
|
-
throw new Error('Batch must be an array');
|
|
17
|
-
}
|
|
18
|
-
// If we have a DB manager, we want to intercept queries for fusion
|
|
19
|
-
// We create a proxy for the DB manager attached to the context
|
|
20
|
-
let batchCtx = ctx;
|
|
21
|
-
if (this.dbManager && ctx.db) {
|
|
22
|
-
// Create a localized context that intercepts DB calls
|
|
23
|
-
// We need to ensure that when `ctx.db.get()` is called, it returns a wrapped adapter
|
|
24
|
-
// But `ctx.db` is the manager itself.
|
|
25
|
-
// We can't easily wrap the manager instance shared across requests.
|
|
26
|
-
// Instead, we can wrap the `ctx.db` property for this request scope.
|
|
27
|
-
const originalDb = ctx.db;
|
|
28
|
-
// Create a proxy for the database manager
|
|
29
|
-
const dbProxy = new Proxy(originalDb, {
|
|
30
|
-
get: (target, prop, receiver) => {
|
|
31
|
-
if (prop === 'get' || prop === 'connect') {
|
|
32
|
-
return (name) => {
|
|
33
|
-
const adapter = target.get(name);
|
|
34
|
-
// Check if we have a coalescer for this connection
|
|
35
|
-
const connName = name || 'default'; // Simplify for now
|
|
36
|
-
let coalescer = this.coalescers.get(connName);
|
|
37
|
-
// In a real per-request batch scope, we should create a new Coalescer
|
|
38
|
-
// OR reset the existing one?
|
|
39
|
-
// Actually, the Coalescer uses a short timeout (next tick).
|
|
40
|
-
// So it is safe to share across concurrent requests IF we want global batching.
|
|
41
|
-
// BUT "auto transaction scope" implies per-request isolation.
|
|
42
|
-
// For "Query Fusion", global batching is even better (cross-request fusion).
|
|
43
|
-
// However, for this task, let's stick to per-request or global safely.
|
|
44
|
-
// Since Coalescer flushes on next tick, sharing it is fine and efficient.
|
|
45
|
-
if (!coalescer) {
|
|
46
|
-
coalescer = new coalescer_1.QueryCoalescer(adapter);
|
|
47
|
-
this.coalescers.set(connName, coalescer);
|
|
48
|
-
}
|
|
49
|
-
// Return a proxy to the adapter that uses the coalescer
|
|
50
|
-
return {
|
|
51
|
-
...adapter,
|
|
52
|
-
query: (query, params) => coalescer.query(query, params),
|
|
53
|
-
isConnected: () => adapter.isConnected(),
|
|
54
|
-
connect: () => adapter.connect(),
|
|
55
|
-
disconnect: () => adapter.disconnect()
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
return Reflect.get(target, prop, receiver);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
// Create a new context object that inherits from original but overrides db
|
|
63
|
-
// We use Object.create to prototype inherit, but ctx is a flat object in QHTTPX.
|
|
64
|
-
// We must shallow copy.
|
|
65
|
-
batchCtx = { ...ctx, db: dbProxy };
|
|
66
|
-
}
|
|
67
|
-
// Helper for internal calls
|
|
68
|
-
// "ctx.call" implementation
|
|
69
|
-
// The user wants: `ctx.call("getUser", { id: 5 })`
|
|
70
|
-
// We attach this to the context
|
|
71
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
|
-
batchCtx.call = async (op, params) => {
|
|
73
|
-
const handler = this.ops.get(op);
|
|
74
|
-
if (!handler) {
|
|
75
|
-
throw new Error(`Unknown operation: ${op}`);
|
|
76
|
-
}
|
|
77
|
-
return handler(params, batchCtx);
|
|
78
|
-
};
|
|
79
|
-
// Execute all ops
|
|
80
|
-
// We can run them in parallel since we want to fuse queries
|
|
81
|
-
const results = await Promise.all(batch.map(async (item) => {
|
|
82
|
-
try {
|
|
83
|
-
const handler = this.ops.get(item.op);
|
|
84
|
-
if (!handler) {
|
|
85
|
-
return { error: `Unknown operation: ${item.op}`, id: item.id };
|
|
86
|
-
}
|
|
87
|
-
const result = await handler(item.params, batchCtx);
|
|
88
|
-
return { result, id: item.id };
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
return { error: (err instanceof Error ? err.message : String(err)), id: item.id };
|
|
92
|
-
}
|
|
93
|
-
}));
|
|
94
|
-
return { results };
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
exports.BatchExecutor = BatchExecutor;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { IncomingMessage } from 'http';
|
|
2
|
-
export type BodyParserOptions = {
|
|
3
|
-
maxBodyBytes?: number;
|
|
4
|
-
};
|
|
5
|
-
export type ParsedBody = {
|
|
6
|
-
body: unknown;
|
|
7
|
-
files?: Record<string, unknown>;
|
|
8
|
-
};
|
|
9
|
-
export interface IBodyParser {
|
|
10
|
-
parse(req: IncomingMessage, options?: BodyParserOptions): Promise<any>;
|
|
11
|
-
}
|
|
12
|
-
export declare class BodyParser {
|
|
13
|
-
static parse(req: IncomingMessage, options?: BodyParserOptions): Promise<any>;
|
|
14
|
-
private static parseMultipart;
|
|
15
|
-
}
|
|
@@ -1,121 +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.BodyParser = void 0;
|
|
7
|
-
const querystring_1 = require("querystring");
|
|
8
|
-
const busboy_1 = __importDefault(require("busboy"));
|
|
9
|
-
class BodyParser {
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
-
static async parse(req, options = {}) {
|
|
12
|
-
const method = (req.method || 'GET').toUpperCase();
|
|
13
|
-
if (method === 'GET' || method === 'HEAD') {
|
|
14
|
-
return { body: undefined };
|
|
15
|
-
}
|
|
16
|
-
const contentType = req.headers['content-type'] || '';
|
|
17
|
-
if (contentType.includes('multipart/form-data')) {
|
|
18
|
-
return this.parseMultipart(req, options);
|
|
19
|
-
}
|
|
20
|
-
const chunks = [];
|
|
21
|
-
let totalBytes = 0;
|
|
22
|
-
const maxBodyBytes = options.maxBodyBytes;
|
|
23
|
-
for await (const chunk of req) {
|
|
24
|
-
const bufferChunk = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
|
|
25
|
-
chunks.push(bufferChunk);
|
|
26
|
-
totalBytes += bufferChunk.length;
|
|
27
|
-
if (maxBodyBytes !== undefined && totalBytes > maxBodyBytes) {
|
|
28
|
-
throw new Error('QHTTPX_BODY_TOO_LARGE');
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (chunks.length === 0) {
|
|
32
|
-
return { body: undefined };
|
|
33
|
-
}
|
|
34
|
-
const buffer = Buffer.concat(chunks);
|
|
35
|
-
if (typeof contentType === 'string' &&
|
|
36
|
-
contentType.includes('application/json')) {
|
|
37
|
-
const text = buffer.toString('utf8');
|
|
38
|
-
try {
|
|
39
|
-
return { body: JSON.parse(text) };
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
throw new Error('QHTTPX_INVALID_JSON');
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (typeof contentType === 'string' &&
|
|
46
|
-
contentType.includes('application/x-www-form-urlencoded')) {
|
|
47
|
-
const text = buffer.toString('utf8');
|
|
48
|
-
return { body: (0, querystring_1.parse)(text) };
|
|
49
|
-
}
|
|
50
|
-
return { body: buffer };
|
|
51
|
-
}
|
|
52
|
-
static parseMultipart(req, options) {
|
|
53
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
54
|
-
return new Promise((resolve, reject) => {
|
|
55
|
-
let bb;
|
|
56
|
-
try {
|
|
57
|
-
bb = (0, busboy_1.default)({ headers: req.headers, limits: { fileSize: options.maxBodyBytes } });
|
|
58
|
-
}
|
|
59
|
-
catch (err) {
|
|
60
|
-
return reject(err);
|
|
61
|
-
}
|
|
62
|
-
const body = {};
|
|
63
|
-
const files = {};
|
|
64
|
-
bb.on('field', (name, val) => {
|
|
65
|
-
if (Object.prototype.hasOwnProperty.call(body, name)) {
|
|
66
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
67
|
-
if (Array.isArray(body[name])) {
|
|
68
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
69
|
-
body[name].push(val);
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
-
body[name] = [body[name], val];
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
body[name] = val;
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
bb.on('file', (name, file, info) => {
|
|
81
|
-
const { filename, encoding, mimeType } = info;
|
|
82
|
-
const chunks = [];
|
|
83
|
-
file.on('data', (chunk) => {
|
|
84
|
-
chunks.push(chunk);
|
|
85
|
-
});
|
|
86
|
-
file.on('end', () => {
|
|
87
|
-
const buffer = Buffer.concat(chunks);
|
|
88
|
-
const fileData = {
|
|
89
|
-
filename,
|
|
90
|
-
encoding,
|
|
91
|
-
mimeType,
|
|
92
|
-
data: buffer,
|
|
93
|
-
size: buffer.length,
|
|
94
|
-
};
|
|
95
|
-
if (Object.prototype.hasOwnProperty.call(files, name)) {
|
|
96
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
97
|
-
if (Array.isArray(files[name])) {
|
|
98
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
99
|
-
files[name].push(fileData);
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
103
|
-
files[name] = [files[name], fileData];
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
files[name] = fileData;
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
bb.on('close', () => {
|
|
112
|
-
resolve({ body, files });
|
|
113
|
-
});
|
|
114
|
-
bb.on('error', (err) => {
|
|
115
|
-
reject(err);
|
|
116
|
-
});
|
|
117
|
-
req.pipe(bb);
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
exports.BodyParser = BodyParser;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Buffer pool for response bodies (small, medium, large).
|
|
3
|
-
* Reuses allocated buffers to reduce GC pressure.
|
|
4
|
-
*/
|
|
5
|
-
export type BufferPoolConfig = {
|
|
6
|
-
smallSize?: number;
|
|
7
|
-
mediumSize?: number;
|
|
8
|
-
largeSize?: number;
|
|
9
|
-
smallPoolSize?: number;
|
|
10
|
-
mediumPoolSize?: number;
|
|
11
|
-
largePoolSize?: number;
|
|
12
|
-
};
|
|
13
|
-
export declare class BufferPool {
|
|
14
|
-
private readonly smallSize;
|
|
15
|
-
private readonly mediumSize;
|
|
16
|
-
private readonly largeSize;
|
|
17
|
-
private readonly smallBuffers;
|
|
18
|
-
private readonly mediumBuffers;
|
|
19
|
-
private readonly largeBuffers;
|
|
20
|
-
private readonly smallPoolSize;
|
|
21
|
-
private readonly mediumPoolSize;
|
|
22
|
-
private readonly largePoolSize;
|
|
23
|
-
constructor(config?: BufferPoolConfig);
|
|
24
|
-
/**
|
|
25
|
-
* Acquire a buffer suitable for the given size.
|
|
26
|
-
* Returns a buffer from the appropriate pool.
|
|
27
|
-
*/
|
|
28
|
-
acquire(size: number): Buffer;
|
|
29
|
-
/**
|
|
30
|
-
* Release a buffer back to the appropriate pool.
|
|
31
|
-
*/
|
|
32
|
-
release(buffer: Buffer): void;
|
|
33
|
-
/**
|
|
34
|
-
* Get the number of available buffers in each pool.
|
|
35
|
-
*/
|
|
36
|
-
getPoolStatus(): {
|
|
37
|
-
small: number;
|
|
38
|
-
medium: number;
|
|
39
|
-
large: number;
|
|
40
|
-
};
|
|
41
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Buffer pool for response bodies (small, medium, large).
|
|
4
|
-
* Reuses allocated buffers to reduce GC pressure.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.BufferPool = void 0;
|
|
8
|
-
class BufferPool {
|
|
9
|
-
constructor(config = {}) {
|
|
10
|
-
this.smallBuffers = [];
|
|
11
|
-
this.mediumBuffers = [];
|
|
12
|
-
this.largeBuffers = [];
|
|
13
|
-
this.smallSize = config.smallSize ?? 4096; // 4KB
|
|
14
|
-
this.mediumSize = config.mediumSize ?? 65536; // 64KB
|
|
15
|
-
this.largeSize = config.largeSize ?? 262144; // 256KB
|
|
16
|
-
this.smallPoolSize = config.smallPoolSize ?? 32;
|
|
17
|
-
this.mediumPoolSize = config.mediumPoolSize ?? 8;
|
|
18
|
-
this.largePoolSize = config.largePoolSize ?? 2;
|
|
19
|
-
// Preallocate buffers
|
|
20
|
-
for (let i = 0; i < this.smallPoolSize; i += 1) {
|
|
21
|
-
this.smallBuffers.push(Buffer.allocUnsafe(this.smallSize));
|
|
22
|
-
}
|
|
23
|
-
for (let i = 0; i < this.mediumPoolSize; i += 1) {
|
|
24
|
-
this.mediumBuffers.push(Buffer.allocUnsafe(this.mediumSize));
|
|
25
|
-
}
|
|
26
|
-
for (let i = 0; i < this.largePoolSize; i += 1) {
|
|
27
|
-
this.largeBuffers.push(Buffer.allocUnsafe(this.largeSize));
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Acquire a buffer suitable for the given size.
|
|
32
|
-
* Returns a buffer from the appropriate pool.
|
|
33
|
-
*/
|
|
34
|
-
acquire(size) {
|
|
35
|
-
if (size <= this.smallSize) {
|
|
36
|
-
return this.smallBuffers.pop() || Buffer.allocUnsafe(this.smallSize);
|
|
37
|
-
}
|
|
38
|
-
if (size <= this.mediumSize) {
|
|
39
|
-
return this.mediumBuffers.pop() || Buffer.allocUnsafe(this.mediumSize);
|
|
40
|
-
}
|
|
41
|
-
return this.largeBuffers.pop() || Buffer.allocUnsafe(this.largeSize);
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Release a buffer back to the appropriate pool.
|
|
45
|
-
*/
|
|
46
|
-
release(buffer) {
|
|
47
|
-
if (buffer.length === this.smallSize && this.smallBuffers.length < this.smallPoolSize) {
|
|
48
|
-
this.smallBuffers.push(buffer);
|
|
49
|
-
}
|
|
50
|
-
else if (buffer.length === this.mediumSize &&
|
|
51
|
-
this.mediumBuffers.length < this.mediumPoolSize) {
|
|
52
|
-
this.mediumBuffers.push(buffer);
|
|
53
|
-
}
|
|
54
|
-
else if (buffer.length === this.largeSize &&
|
|
55
|
-
this.largeBuffers.length < this.largePoolSize) {
|
|
56
|
-
this.largeBuffers.push(buffer);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Get the number of available buffers in each pool.
|
|
61
|
-
*/
|
|
62
|
-
getPoolStatus() {
|
|
63
|
-
return {
|
|
64
|
-
small: this.smallBuffers.length,
|
|
65
|
-
medium: this.mediumBuffers.length,
|
|
66
|
-
large: this.largeBuffers.length,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
exports.BufferPool = BufferPool;
|
package/dist/src/core/config.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.loadConfig = loadConfig;
|
|
4
|
-
function loadConfig(options = {}) {
|
|
5
|
-
const env = options.env ?? process.env;
|
|
6
|
-
const defaults = options.defaults ?? {};
|
|
7
|
-
const prefix = options.prefix ?? 'QHTTPX_';
|
|
8
|
-
const getNumber = (key) => {
|
|
9
|
-
const value = env[prefix + key];
|
|
10
|
-
if (!value) {
|
|
11
|
-
return undefined;
|
|
12
|
-
}
|
|
13
|
-
const n = Number(value);
|
|
14
|
-
if (!Number.isFinite(n) || n <= 0) {
|
|
15
|
-
return undefined;
|
|
16
|
-
}
|
|
17
|
-
return n;
|
|
18
|
-
};
|
|
19
|
-
const getBoolean = (key) => {
|
|
20
|
-
const value = env[prefix + key];
|
|
21
|
-
if (!value) {
|
|
22
|
-
return undefined;
|
|
23
|
-
}
|
|
24
|
-
const lower = value.toLowerCase();
|
|
25
|
-
if (lower === 'true' || lower === '1') {
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
if (lower === 'false' || lower === '0') {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
return undefined;
|
|
32
|
-
};
|
|
33
|
-
const maxConcurrency = getNumber('MAX_CONCURRENCY');
|
|
34
|
-
const requestTimeoutMs = getNumber('REQUEST_TIMEOUT_MS');
|
|
35
|
-
const maxMemoryBytes = getNumber('MAX_MEMORY_BYTES');
|
|
36
|
-
const maxBodyBytes = getNumber('MAX_BODY_BYTES');
|
|
37
|
-
const keepAliveTimeoutMs = getNumber('KEEP_ALIVE_TIMEOUT_MS');
|
|
38
|
-
const headersTimeoutMs = getNumber('HEADERS_TIMEOUT_MS');
|
|
39
|
-
const metricsEnabled = getBoolean('METRICS_ENABLED');
|
|
40
|
-
return {
|
|
41
|
-
...defaults,
|
|
42
|
-
maxConcurrency: maxConcurrency ?? defaults.maxConcurrency,
|
|
43
|
-
requestTimeoutMs: requestTimeoutMs ?? defaults.requestTimeoutMs,
|
|
44
|
-
maxMemoryBytes: maxMemoryBytes ?? defaults.maxMemoryBytes,
|
|
45
|
-
maxBodyBytes: maxBodyBytes ?? defaults.maxBodyBytes,
|
|
46
|
-
keepAliveTimeoutMs: keepAliveTimeoutMs ?? defaults.keepAliveTimeoutMs,
|
|
47
|
-
headersTimeoutMs: headersTimeoutMs ?? defaults.headersTimeoutMs,
|
|
48
|
-
metricsEnabled: metricsEnabled ?? defaults.metricsEnabled,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { HttpError } from './types';
|
|
2
|
-
export declare class BadRequestException extends HttpError {
|
|
3
|
-
constructor(message?: string, details?: unknown);
|
|
4
|
-
}
|
|
5
|
-
export declare class UnauthorizedException extends HttpError {
|
|
6
|
-
constructor(message?: string, details?: unknown);
|
|
7
|
-
}
|
|
8
|
-
export declare class ForbiddenException extends HttpError {
|
|
9
|
-
constructor(message?: string, details?: unknown);
|
|
10
|
-
}
|
|
11
|
-
export declare class NotFoundException extends HttpError {
|
|
12
|
-
constructor(message?: string, details?: unknown);
|
|
13
|
-
}
|
|
14
|
-
export declare class MethodNotAllowedException extends HttpError {
|
|
15
|
-
constructor(message?: string, details?: unknown);
|
|
16
|
-
}
|
|
17
|
-
export declare class ConflictException extends HttpError {
|
|
18
|
-
constructor(message?: string, details?: unknown);
|
|
19
|
-
}
|
|
20
|
-
export declare class PayloadTooLargeException extends HttpError {
|
|
21
|
-
constructor(message?: string, details?: unknown);
|
|
22
|
-
}
|
|
23
|
-
export declare class UnsupportedMediaTypeException extends HttpError {
|
|
24
|
-
constructor(message?: string, details?: unknown);
|
|
25
|
-
}
|
|
26
|
-
export declare class TooManyRequestsException extends HttpError {
|
|
27
|
-
constructor(message?: string, details?: unknown);
|
|
28
|
-
}
|
|
29
|
-
export declare class InternalServerErrorException extends HttpError {
|
|
30
|
-
constructor(message?: string, details?: unknown);
|
|
31
|
-
}
|
|
32
|
-
export declare class ServiceUnavailableException extends HttpError {
|
|
33
|
-
constructor(message?: string, details?: unknown);
|
|
34
|
-
}
|
package/dist/src/core/errors.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ServiceUnavailableException = exports.InternalServerErrorException = exports.TooManyRequestsException = exports.UnsupportedMediaTypeException = exports.PayloadTooLargeException = exports.ConflictException = exports.MethodNotAllowedException = exports.NotFoundException = exports.ForbiddenException = exports.UnauthorizedException = exports.BadRequestException = void 0;
|
|
4
|
-
const types_1 = require("./types");
|
|
5
|
-
class BadRequestException extends types_1.HttpError {
|
|
6
|
-
constructor(message = 'Bad Request', details) {
|
|
7
|
-
super(400, message, { code: 'BAD_REQUEST', details });
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
exports.BadRequestException = BadRequestException;
|
|
11
|
-
class UnauthorizedException extends types_1.HttpError {
|
|
12
|
-
constructor(message = 'Unauthorized', details) {
|
|
13
|
-
super(401, message, { code: 'UNAUTHORIZED', details });
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
exports.UnauthorizedException = UnauthorizedException;
|
|
17
|
-
class ForbiddenException extends types_1.HttpError {
|
|
18
|
-
constructor(message = 'Forbidden', details) {
|
|
19
|
-
super(403, message, { code: 'FORBIDDEN', details });
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
exports.ForbiddenException = ForbiddenException;
|
|
23
|
-
class NotFoundException extends types_1.HttpError {
|
|
24
|
-
constructor(message = 'Not Found', details) {
|
|
25
|
-
super(404, message, { code: 'NOT_FOUND', details });
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
exports.NotFoundException = NotFoundException;
|
|
29
|
-
class MethodNotAllowedException extends types_1.HttpError {
|
|
30
|
-
constructor(message = 'Method Not Allowed', details) {
|
|
31
|
-
super(405, message, { code: 'METHOD_NOT_ALLOWED', details });
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
exports.MethodNotAllowedException = MethodNotAllowedException;
|
|
35
|
-
class ConflictException extends types_1.HttpError {
|
|
36
|
-
constructor(message = 'Conflict', details) {
|
|
37
|
-
super(409, message, { code: 'CONFLICT', details });
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
exports.ConflictException = ConflictException;
|
|
41
|
-
class PayloadTooLargeException extends types_1.HttpError {
|
|
42
|
-
constructor(message = 'Payload Too Large', details) {
|
|
43
|
-
super(413, message, { code: 'PAYLOAD_TOO_LARGE', details });
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
exports.PayloadTooLargeException = PayloadTooLargeException;
|
|
47
|
-
class UnsupportedMediaTypeException extends types_1.HttpError {
|
|
48
|
-
constructor(message = 'Unsupported Media Type', details) {
|
|
49
|
-
super(415, message, { code: 'UNSUPPORTED_MEDIA_TYPE', details });
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
exports.UnsupportedMediaTypeException = UnsupportedMediaTypeException;
|
|
53
|
-
class TooManyRequestsException extends types_1.HttpError {
|
|
54
|
-
constructor(message = 'Too Many Requests', details) {
|
|
55
|
-
super(429, message, { code: 'TOO_MANY_REQUESTS', details });
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
exports.TooManyRequestsException = TooManyRequestsException;
|
|
59
|
-
class InternalServerErrorException extends types_1.HttpError {
|
|
60
|
-
constructor(message = 'Internal Server Error', details) {
|
|
61
|
-
super(500, message, { code: 'INTERNAL_SERVER_ERROR', details });
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
exports.InternalServerErrorException = InternalServerErrorException;
|
|
65
|
-
class ServiceUnavailableException extends types_1.HttpError {
|
|
66
|
-
constructor(message = 'Service Unavailable', details) {
|
|
67
|
-
super(503, message, { code: 'SERVICE_UNAVAILABLE', details });
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
exports.ServiceUnavailableException = ServiceUnavailableException;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { QHTTPXContext } from './types';
|
|
2
|
-
export interface RequestFusionOptions {
|
|
3
|
-
windowMs?: number;
|
|
4
|
-
vary?: string[];
|
|
5
|
-
}
|
|
6
|
-
export declare class RequestFusion {
|
|
7
|
-
private inflight;
|
|
8
|
-
private cache;
|
|
9
|
-
private options;
|
|
10
|
-
constructor(options?: boolean | RequestFusionOptions);
|
|
11
|
-
coalesce(ctx: QHTTPXContext, next: (ctx: QHTTPXContext) => Promise<void> | void): Promise<void>;
|
|
12
|
-
private applyResult;
|
|
13
|
-
private getKey;
|
|
14
|
-
}
|