@juit/pgproxy-server 1.0.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.
package/README.md ADDED
@@ -0,0 +1,8 @@
1
+ # PostgreSQL Proxy Server
2
+
3
+ This package provides the core of the PGProxy HTTP and WebSocket server to
4
+ be used in connection with PGProxy clients.
5
+
6
+ * [PGProxy](https://github.com/juitnow/juit-pgproxy/blob/main/README.md)
7
+ * [Copyright Notice](https://github.com/juitnow/juit-pgproxy/blob/main/NOTICE.md)
8
+ * [License](https://github.com/juitnow/juit-pgproxy/blob/main/NOTICE.md)
package/dist/index.cjs ADDED
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
15
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
+
17
+ // index.ts
18
+ var src_exports = {};
19
+ module.exports = __toCommonJS(src_exports);
20
+ __reExport(src_exports, require("./server.cjs"), module.exports);
21
+ // Annotate the CommonJS export names for ESM import in node:
22
+ 0 && (module.exports = {
23
+ ...require("./server.cjs")
24
+ });
25
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAEA,wBAAc,yBAFd;",
5
+ "names": []
6
+ }
@@ -0,0 +1,20 @@
1
+ import type { ConnectionQueryResult } from '@juit/pgproxy-pool';
2
+ export * from './server';
3
+ export interface Request {
4
+ id: string;
5
+ query: string;
6
+ params?: (string | null)[];
7
+ }
8
+ export interface PositiveResponse extends ConnectionQueryResult {
9
+ statusCode: 200;
10
+ error?: never;
11
+ }
12
+ export type NegativeResponse = {
13
+ [key in keyof ConnectionQueryResult]?: never;
14
+ } & {
15
+ statusCode: 400 | 500;
16
+ error: string;
17
+ };
18
+ export type Response = {
19
+ id: string;
20
+ } & (PositiveResponse | NegativeResponse);
package/dist/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ // index.ts
2
+ export * from "./server.mjs";
3
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "mappings": ";AAEA,cAAc;",
5
+ "names": []
6
+ }
@@ -0,0 +1,390 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // server.ts
31
+ var server_exports = {};
32
+ __export(server_exports, {
33
+ Server: () => Server
34
+ });
35
+ module.exports = __toCommonJS(server_exports);
36
+ var import_node_assert = __toESM(require("node:assert"));
37
+ var import_node_crypto = require("node:crypto");
38
+ var import_node_http = require("node:http");
39
+ var import_node_path = require("node:path");
40
+ var import_node_querystring = require("node:querystring");
41
+ var import_pgproxy_pool = require("@juit/pgproxy-pool");
42
+ var import_ws = require("ws");
43
+ var import_token = require("./token.cjs");
44
+ var ServerImpl = class {
45
+ /* Keep those as private class members, they contain auth data... */
46
+ #tokens = {};
47
+ #pool;
48
+ #secret;
49
+ _server;
50
+ _logger;
51
+ _healthCheck;
52
+ _backlog;
53
+ _address;
54
+ _port;
55
+ _started = false;
56
+ _stopped = false;
57
+ constructor(logger, options) {
58
+ const { address, port, backlog, secret, healthCheck, pool, ...serverOptions } = options;
59
+ this.#pool = new import_pgproxy_pool.ConnectionPool(logger, pool);
60
+ this.#secret = secret;
61
+ this._healthCheck = healthCheck ? (0, import_node_path.resolve)("/", healthCheck) : null;
62
+ this._backlog = backlog;
63
+ this._address = address;
64
+ this._logger = logger;
65
+ this._port = port;
66
+ this._server = (0, import_node_http.createServer)(serverOptions);
67
+ const wss = new import_ws.WebSocketServer({ noServer: true });
68
+ this._server.on("request", (req, res) => this._requestHandler(req, res));
69
+ this._server.on("upgrade", (req, sock, head) => this._upgradeHandler(req, sock, head, wss));
70
+ this._server.on("close", () => {
71
+ wss.close((wssError) => {
72
+ if (wssError)
73
+ logger.error("Error closing WebSocket server:", wssError);
74
+ try {
75
+ this.#pool.stop();
76
+ } catch (poolError) {
77
+ logger.error("Error closing connection pool:", poolError);
78
+ } finally {
79
+ this._logger.info("DB proxy server stopped");
80
+ }
81
+ });
82
+ });
83
+ }
84
+ _catchError(message) {
85
+ return (error) => this._logger.error(message, error);
86
+ }
87
+ /* ======================================================================== *
88
+ * PROPERTIES *
89
+ * ======================================================================== */
90
+ get address() {
91
+ const address = this._server?.address();
92
+ (0, import_node_assert.default)(address, "Server not started");
93
+ return address;
94
+ }
95
+ /* coverage ignore next */
96
+ get url() {
97
+ const { address, family, port } = this.address;
98
+ if (family === "IPv6")
99
+ return new URL(`http://[${address}]:${port}/`);
100
+ if (family === "IPv4")
101
+ return new URL(`http://${address}:${port}/`);
102
+ throw new Error(`Unsupported address family "${family}"`);
103
+ }
104
+ get stats() {
105
+ return this.#pool.stats;
106
+ }
107
+ /* ======================================================================== *
108
+ * LIFECYCLE METHODS *
109
+ * ======================================================================== */
110
+ async start() {
111
+ (0, import_node_assert.default)(!this._started, "Server already started");
112
+ this._started = true;
113
+ this._logger.debug("Starting server");
114
+ await this.#pool.start();
115
+ await new Promise((resolve2, reject) => {
116
+ this._server.on("error", reject);
117
+ this._server.listen(this._port, this._address, this._backlog, () => {
118
+ this._server.off("error", reject);
119
+ resolve2();
120
+ });
121
+ });
122
+ this._server.on(
123
+ "error",
124
+ /* coverage ignore next */
125
+ (error) => {
126
+ this._logger.error("Server Error:", error);
127
+ this.stop().catch(this._catchError("Error stopping server")).finally(() => process.exit(1));
128
+ }
129
+ );
130
+ setInterval(() => {
131
+ const now = Date.now();
132
+ for (const [token, expiry] of Object.entries(this.#tokens)) {
133
+ if (expiry < now)
134
+ delete this.#tokens[token];
135
+ }
136
+ }).unref();
137
+ this._logger.info(`DB proxy server started at ${this.url}`);
138
+ if (this._healthCheck) {
139
+ this._logger.info(`Unauthenticated health check available at "${this._healthCheck}"`);
140
+ }
141
+ this._logger.info("Connection pool options");
142
+ for (const [key, value] of Object.entries(this.#pool.configuration)) {
143
+ const name = key.replaceAll(/[A-Z]/g, (c) => ` ${c.toLowerCase()}`);
144
+ this._logger.info(`- ${name}: ${value}`);
145
+ }
146
+ return this;
147
+ }
148
+ async stop() {
149
+ (0, import_node_assert.default)(this._started, "Server never started");
150
+ (0, import_node_assert.default)(!this._stopped, "Server already stopped");
151
+ this._stopped = true;
152
+ this._logger.info(`Stopping DB proxy server at "${this.url}"`);
153
+ await new Promise(
154
+ /* coverage ignore next */
155
+ (resolve2, reject) => {
156
+ this._server.close((error) => error ? reject(error) : resolve2());
157
+ }
158
+ );
159
+ }
160
+ /* ======================================================================== *
161
+ * REQUEST HANDLING *
162
+ * ======================================================================== */
163
+ _sendResponse(object, statusCode, request, response) {
164
+ new Promise((resolve2, reject) => {
165
+ try {
166
+ const json = JSON.stringify(object);
167
+ const buffer = Buffer.from(json, "utf-8");
168
+ response.statusCode = statusCode;
169
+ response.setHeader("content-type", "application/json");
170
+ response.setHeader("content-length", buffer.length);
171
+ response.write(buffer, (error) => {
172
+ if (error)
173
+ reject(error);
174
+ else
175
+ resolve2();
176
+ });
177
+ } catch (error) {
178
+ reject(error);
179
+ }
180
+ }).catch(
181
+ /* coverage ignore next */
182
+ (error) => {
183
+ this._logger.error(`Error handling request "${request.url}"`, error);
184
+ response.statusCode = 500;
185
+ }
186
+ ).finally(() => response.end());
187
+ }
188
+ _healthCheckHandler(request, response) {
189
+ if (request.url !== this._healthCheck) {
190
+ response.statusCode = 404;
191
+ return void response.end();
192
+ }
193
+ void Promise.resolve().then(async () => {
194
+ const stats = { ...this.stats };
195
+ const start = process.hrtime.bigint();
196
+ const connection = await this.#pool.acquire();
197
+ const queryStart = process.hrtime.bigint();
198
+ try {
199
+ await connection.query("SELECT now()");
200
+ } finally {
201
+ this.#pool.release(connection);
202
+ }
203
+ const queryEnd = process.hrtime.bigint();
204
+ const latency = Math.floor(Number(queryEnd - start) / 1e4) / 100;
205
+ const connTime = Math.floor(Number(queryStart - start) / 1e4) / 100;
206
+ const queryTime = Math.floor(Number(queryEnd - queryStart) / 1e4) / 100;
207
+ return { ...stats, latency, connTime, queryTime };
208
+ }).then((data) => {
209
+ const { connTime, queryTime, ...stats } = data;
210
+ this._sendResponse(stats, 200, request, response);
211
+ this._logger.info(`Handled Health check with latency of ${data.latency} ms (connection ${connTime} ms, query ${queryTime} ms)`);
212
+ });
213
+ }
214
+ _requestHandler(request, response) {
215
+ if (request.method === "GET")
216
+ return this._healthCheckHandler(request, response);
217
+ const statusCode = this._validateAuth(request);
218
+ if (statusCode !== 200) {
219
+ response.statusCode = statusCode;
220
+ return void response.end();
221
+ }
222
+ if (request.method !== "POST") {
223
+ response.statusCode = 405;
224
+ return void response.end();
225
+ }
226
+ if (request.headers["content-type"] !== "application/json") {
227
+ response.statusCode = 415;
228
+ return void response.end();
229
+ }
230
+ const now = process.hrtime.bigint();
231
+ void Promise.resolve().then(async () => {
232
+ const string = await this._readRequest(request);
233
+ const payload = this._validatePayload(string);
234
+ if (!payload.valid) {
235
+ return { id: payload.id, statusCode: 400, error: payload.error };
236
+ }
237
+ let connection;
238
+ try {
239
+ const now2 = process.hrtime.bigint();
240
+ connection = await this.#pool.acquire();
241
+ const ms = Number(process.hrtime.bigint() - now2) / 1e6;
242
+ this._logger.debug(`Acquired connection ${connection.id} in ${ms} ms`);
243
+ } catch (error) {
244
+ this._logger.error("Error acquiring connection:", error);
245
+ return { id: payload.id, statusCode: 500, error: "Error acquiring connection" };
246
+ }
247
+ try {
248
+ const result = await connection.query(payload.query, payload.params);
249
+ return { ...result, statusCode: 200, id: payload.id };
250
+ } catch (error) {
251
+ return { id: payload.id, statusCode: 400, error: error.message };
252
+ } finally {
253
+ this.#pool.release(connection);
254
+ }
255
+ }).then((data) => {
256
+ this._sendResponse(data, data.statusCode, request, response);
257
+ const ms = Math.floor(Number(process.hrtime.bigint() - now) / 1e4) / 100;
258
+ this._logger.info(`Handled "${data.command}" HTTP request in ${ms} ms`);
259
+ });
260
+ }
261
+ _upgradeHandler(request, socket, head, wss) {
262
+ const statusCode = this._validateAuth(request);
263
+ if (statusCode !== 200) {
264
+ const onSocketError = (error) => {
265
+ this._logger.error("Socket error", error);
266
+ socket.destroy();
267
+ };
268
+ socket.on("error", onSocketError);
269
+ socket.write(`HTTP/1.1 ${statusCode} ${import_node_http.STATUS_CODES[statusCode]}\r
270
+ \r
271
+ `);
272
+ socket.destroy();
273
+ socket.off("error", onSocketError);
274
+ return;
275
+ }
276
+ wss.handleUpgrade(request, socket, head, (ws) => {
277
+ const promise = this.#pool.acquire().catch(
278
+ /* coverage ignore next */
279
+ (error) => {
280
+ this._logger.error("Error acquiring connection for WebSocket:", error);
281
+ ws.close();
282
+ }
283
+ );
284
+ const release = () => void promise.then((connection) => connection && this.#pool.release(connection)).catch(this._catchError("Error releasing connection for WebSocket:"));
285
+ const send = (data) => {
286
+ const message = JSON.stringify(data);
287
+ ws.send(message, (error) => {
288
+ if (error) {
289
+ this._logger.error("Error sending WebSocket response:", error);
290
+ ws.close();
291
+ }
292
+ });
293
+ };
294
+ ws.on(
295
+ "error",
296
+ /* coverage ignore next */
297
+ (error) => {
298
+ this._logger.error("WebSocket error", error);
299
+ release();
300
+ }
301
+ );
302
+ ws.on("close", (code, reason) => {
303
+ const extra = reason.toString("utf-8");
304
+ extra ? this._logger.info(`WebSocket closed (${code}):`, extra) : this._logger.info(`WebSocket closed (${code}):`);
305
+ release();
306
+ });
307
+ ws.on("message", (data) => {
308
+ const now = process.hrtime.bigint();
309
+ const payload = this._validatePayload(data.toString("utf-8"));
310
+ if (!payload.valid) {
311
+ send({ id: payload.id, statusCode: 400, error: payload.error });
312
+ } else {
313
+ promise.then(async (connection) => {
314
+ if (!connection)
315
+ return;
316
+ try {
317
+ const result = await connection.query(payload.query, payload.params);
318
+ const ms = Math.floor(Number(process.hrtime.bigint() - now) / 1e4) / 100;
319
+ this._logger.info(`Handled "${result.command}" WebSocket request in ${ms} ms`);
320
+ return send({ ...result, statusCode: 200, id: payload.id });
321
+ } catch (error) {
322
+ return send({ id: payload.id, statusCode: 400, error: error.message });
323
+ }
324
+ }).catch(this._catchError("Error querying in websocket"));
325
+ }
326
+ });
327
+ });
328
+ }
329
+ /* ======================================================================== *
330
+ * INTERNALS *
331
+ * ======================================================================== */
332
+ /** Read the body of an HTTP request fully */
333
+ _readRequest(stream) {
334
+ return new Promise((resolve2, reject) => {
335
+ const buffers = [];
336
+ stream.on(
337
+ "error",
338
+ /* coverage ignore next */
339
+ (error) => reject(error)
340
+ );
341
+ stream.on("data", (buffer) => buffers.push(buffer));
342
+ stream.on("end", () => resolve2(Buffer.concat(buffers)));
343
+ if (stream.isPaused())
344
+ stream.resume();
345
+ }).then((buffer) => buffer.toString("utf-8"));
346
+ }
347
+ /** Parse a payload string as JSON and validate it */
348
+ _validatePayload(string) {
349
+ try {
350
+ const payload = JSON.parse(string || "{}");
351
+ const id = payload?.id ? `${payload.id}` : (0, import_node_crypto.randomUUID)();
352
+ if (!payload?.query) {
353
+ return { id, valid: false, error: "Invalid payload (or query missing)" };
354
+ }
355
+ if (typeof payload.query !== "string") {
356
+ return { id, valid: false, error: "Query is not a string" };
357
+ }
358
+ if (payload.params && !Array.isArray(payload.params)) {
359
+ return { id, valid: false, error: "Parameters are not an array" };
360
+ }
361
+ return { id, valid: true, query: payload.query, params: payload.params };
362
+ } catch (error) {
363
+ return { id: (0, import_node_crypto.randomUUID)(), valid: false, error: "Error parsing JSON" };
364
+ }
365
+ }
366
+ /** Validate a request (it must have an "auth" query parameter) */
367
+ _validateAuth(request) {
368
+ const auth = (0, import_node_querystring.parse)(request.url.split("?")[1] || "").auth;
369
+ if (typeof auth !== "string")
370
+ return 401;
371
+ try {
372
+ const token = (0, import_token.verifyToken)(auth, this.#secret);
373
+ if (token in this.#tokens) {
374
+ this._logger.error("Attempted to reuse an existing token");
375
+ return 403;
376
+ }
377
+ this.#tokens[token] = Date.now() + 6e4;
378
+ return 200;
379
+ } catch (error) {
380
+ this._logger.error(error);
381
+ return 403;
382
+ }
383
+ }
384
+ };
385
+ var Server = ServerImpl;
386
+ // Annotate the CommonJS export names for ESM import in node:
387
+ 0 && (module.exports = {
388
+ Server
389
+ });
390
+ //# sourceMappingURL=server.cjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/server.ts"],
4
+ "mappings": "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",
5
+ "names": ["assert", "resolve", "now", "parseQueryString"]
6
+ }
@@ -0,0 +1,30 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
4
+ import type { ConnectionPoolOptions, ConnectionPoolStats, Logger } from '@juit/pgproxy-pool';
5
+ import type { ServerOptions as HTTPOptions } from 'node:http';
6
+ import type { AddressInfo } from 'node:net';
7
+ export interface ServerOptions extends HTTPOptions {
8
+ /** The secret used to authenticate clients */
9
+ secret: string;
10
+ /** The path used to provide stats and a healthcheck via GET */
11
+ healthCheck?: string;
12
+ /** The address where this server will be bound to */
13
+ address?: string;
14
+ /** The port number where this server will be bound to */
15
+ port?: number;
16
+ /** The maximum length of the queue of pending connections */
17
+ backlog?: number;
18
+ /** Options for the connection pool backing this server */
19
+ pool?: ConnectionPoolOptions;
20
+ }
21
+ export interface Server {
22
+ readonly url: URL;
23
+ readonly address: AddressInfo;
24
+ readonly stats: ConnectionPoolStats;
25
+ start(): Promise<Server>;
26
+ stop(): Promise<void>;
27
+ }
28
+ export declare const Server: {
29
+ new (logger: Logger, options: ServerOptions): Server;
30
+ };