Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@electric-sql/pglite-socket

Package Overview
Dependencies
Maintainers
4
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@electric-sql/pglite-socket - npm Package Compare versions

Comparing version
0.0.22
to
0.1.0
+3
dist/chunk-NSUMFCRM.js
import{createServer as m}from"net";var b=6e4,c=class{constructor(s,e=!1){this.queue=[];this.processing=!1;this.lastHandlerId=null;this.db=s,this.debug=e}log(s,...e){this.debug&&console.log(`[QueryQueueManager] ${s}`,...e)}async enqueue(s,e,i){return new Promise((t,r)=>{let o={handlerId:s,message:e,resolve:t,reject:r,timestamp:Date.now(),onData:i};this.queue.push(o),this.log(`enqueued query from handler #${s}, queue size: ${this.queue.length}`),this.processing||this.processQueue()})}async processQueue(){if(!(this.processing||this.queue.length===0)){for(this.processing=!0;this.queue.length>0;){let s;if(this.db.isInTransaction()&&this.lastHandlerId){let t=this.queue.findIndex(r=>r.handlerId===this.lastHandlerId);t===-1?(this.log("transaction started, but no query from the same handler id found in queue",this.lastHandlerId),s=null):s=this.queue.splice(t,1)[0]}else s=this.queue.shift();if(!s)break;let e=Date.now()-s.timestamp;this.log(`processing query from handler #${s.handlerId} (waited ${e}ms)`);let i=0;try{await this.db.runExclusive(async()=>await this.db.execProtocolRawStream(s.message,{onRawData:t=>{i+=t.length,s.onData(t)}}))}catch(t){this.log(`query from handler #${s.handlerId} failed:`,t),s.reject(t);return}this.log(`query from handler #${s.handlerId} completed, ${i} bytes`),this.lastHandlerId=s.handlerId,s.resolve(i)}this.processing=!1,this.log("queue processing complete, queue length is",this.queue.length)}}getQueueLength(){return this.queue.length}clearQueueForHandler(s){let e=this.queue.length;this.queue=this.queue.filter(t=>t.handlerId===s?(t.reject(new Error("Handler disconnected")),!1):!0);let i=e-this.queue.length;i>0&&this.log(`cleared ${i} queries for handler #${s}`)}async clearTransactionIfNeeded(s){this.db.isInTransaction()&&this.lastHandlerId===s&&(await this.db.exec("ROLLBACK"),this.lastHandlerId=null,await this.processQueue())}},l=class l extends EventTarget{constructor(e){super();this.socket=null;this.active=!1;this.messageBuffer=Buffer.alloc(0);this.lastActivityTime=Date.now();this.queryQueue=e.queryQueue,this.closeOnDetach=e.closeOnDetach??!1,this.inspect=e.inspect??!1,this.debug=e.debug??!1,this.idleTimeout=e.idleTimeout??0,this.id=l.nextHandlerId++,this.log("constructor: created new handler")}get handlerId(){return this.id}log(e,...i){this.debug&&console.log(`[PGLiteSocketHandler#${this.id}] ${e}`,...i)}async attach(e){if(this.log(`attach: attaching socket from ${e.remoteAddress}:${e.remotePort}`),this.socket)throw new Error("Socket already attached");return this.socket=e,this.active=!0,this.lastActivityTime=Date.now(),e.setNoDelay(!0),this.idleTimeout>0&&this.resetIdleTimer(),this.log("attach: setting up socket event handlers"),e.on("data",i=>{this.lastActivityTime=Date.now(),this.resetIdleTimer(),setImmediate(async()=>{try{await this.handleData(i)}catch(t){this.log("socket on data error: ",t),this.handleError(t)}})}),e.on("error",i=>{setImmediate(()=>this.handleError(i))}),e.on("close",()=>{setImmediate(()=>this.handleClose())}),this.log("attach: socket handler ready"),this}resetIdleTimer(){this.idleTimeout<=0||(this.idleTimer&&clearTimeout(this.idleTimer),this.idleTimer=setTimeout(()=>{let e=Date.now()-this.lastActivityTime;this.log(`idle timeout after ${e}ms`),this.handleError(new Error("Idle timeout"))},this.idleTimeout))}async detach(e){if(this.log(`detach: detaching socket, close=${e??this.closeOnDetach}`),this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=void 0),this.queryQueue.clearQueueForHandler(this.id),await this.queryQueue.clearTransactionIfNeeded(this.id),!this.socket)return this.log("detach: no socket attached, nothing to do"),this;if(this.socket.removeAllListeners("data"),this.socket.removeAllListeners("error"),this.socket.removeAllListeners("close"),(e??this.closeOnDetach)&&this.socket.writable){this.log("detach: closing socket");try{this.socket.end(),this.socket.destroy()}catch(i){this.log("detach: error closing socket:",i)}}return this.socket=null,this.active=!1,this.messageBuffer=Buffer.alloc(0),this.log("detach: handler cleaned up"),this}get isAttached(){return this.socket!==null}async handleData(e){if(!this.socket||!this.active)return this.log("handleData: no active socket, ignoring data"),0;this.log(`handleData: received ${e.length} bytes`),this.messageBuffer=Buffer.concat([this.messageBuffer,e]),this.inspectData("incoming",e);try{let i=0;for(;this.messageBuffer.length>0;){let t=0,r=!1;if(this.messageBuffer.length>=4){let n=this.messageBuffer.readInt32BE(0);if(this.messageBuffer.length>=8){let a=this.messageBuffer.readInt32BE(4);(a===196608||a===196608)&&(t=n,r=this.messageBuffer.length>=t)}!r&&this.messageBuffer.length>=5&&(t=1+this.messageBuffer.readInt32BE(1),r=this.messageBuffer.length>=t)}if(!r||t===0){this.log(`handleData: incomplete message, buffering ${this.messageBuffer.length} bytes`);break}let o=this.messageBuffer.slice(0,t);if(this.messageBuffer=this.messageBuffer.slice(t),this.log(`handleData: processing message of ${o.length} bytes`),!this.active||!this.socket){this.log("handleData: socket no longer active, stopping processing");break}let h;if(await this.queryQueue.enqueue(this.id,new Uint8Array(o),n=>{this.log(`handleData: received ${n.length} bytes from PGlite`),this.inspectData("outgoing",n),n.length>0&&this.socket&&this.socket.writable&&this.active&&(this.log("handleData: writing response to socket"),this.socket?.writable?this.socket.write(Buffer.from(n),a=>{a?(this.log("handleData: error writing to socket:",a),h=a):this.log(`handleData: socket sent: ${n.length} bytes`)}):this.log("handleData: socket no longer writable")),i+=n.length}),h)throw h}return this.dispatchEvent(new CustomEvent("data",{detail:{incoming:e.length,outgoing:i}})),i}catch(i){throw this.log("handleData: error processing data:",i),i}}handleError(e){if(!this.active){this.log("handleError: handler not active, ignoring error");return}e.message?.includes("ECONNRESET")?this.log("handleError: client disconnected (ECONNRESET) - normal behavior"):e.message?.includes("Idle timeout")?this.log("handleError: connection idle timeout"):this.log("handleError:",e),this.active=!1,this.dispatchEvent(new CustomEvent("error",{detail:e})),this.detach(!0)}handleClose(){this.log("handleClose: socket closed"),this.active=!1,this.dispatchEvent(new CustomEvent("close")),this.detach(!1)}inspectData(e,i){if(this.inspect){console.log("-".repeat(75)),console.log(e==="incoming"?"-> incoming":"<- outgoing",i.length,"bytes");for(let t=0;t<i.length;t+=16){let r=Math.min(16,i.length-t),o="";for(let n=0;n<16;n++)if(n<r){let a=i[t+n];o+=a.toString(16).padStart(2,"0")+" "}else o+=" ";let h="";for(let n=0;n<r;n++){let a=i[t+n];h+=a>=32&&a<=126?String.fromCharCode(a):"."}console.log(`${t.toString(16).padStart(8,"0")} ${o} ${h}`)}}}};l.nextHandlerId=1;var d=l,u=class extends EventTarget{constructor(e){super();this.server=null;this.active=!1;this.handlers=new Set;this.db=e.db,e.path?this.path=e.path:(typeof e.port=="number"?this.port=e.port??e.port:this.port=5432,this.host=e.host||"127.0.0.1"),this.inspect=e.inspect??!1,this.debug=e.debug??!1,this.idleTimeout=e.idleTimeout??0,this.maxConnections=e.maxConnections??1,this.queryQueue=new c(this.db,this.debug),this.log(`constructor: created server on ${this.getServerConn()}`),this.log(`constructor: max connections: ${this.maxConnections}`),this.idleTimeout>0&&this.log(`constructor: idle timeout: ${this.idleTimeout}ms`)}log(e,...i){this.debug&&console.log(`[PGLiteSocketServer] ${e}`,...i)}async start(){if(this.log(`start: starting server on ${this.getServerConn()}`),this.server)throw new Error("Socket server already started");return await this.db.waitReady,this.active=!0,this.server=m(e=>{setImmediate(()=>this.handleConnection(e))}),this.server.maxConnections=this.maxConnections,new Promise((e,i)=>{if(!this.server)return i(new Error("Server not initialized"));if(this.server.on("error",t=>{this.log("start: server error:",t),this.dispatchEvent(new CustomEvent("error",{detail:t})),this.active||i(t)}),this.path)this.server.listen(this.path,()=>{this.log(`start: server listening on ${this.getServerConn()}`),this.dispatchEvent(new CustomEvent("listening",{detail:{path:this.path}})),e()});else{let t=this.server;t.listen(this.port,this.host,()=>{let r=t.address();if(r===null||typeof r!="object")throw Error("Expected address info");this.port=r.port,this.log(`start: server listening on ${this.getServerConn()}`),this.dispatchEvent(new CustomEvent("listening",{detail:{port:this.port,host:this.host}})),e()})}})}getServerConn(){return this.path?this.path:`${this.host}:${this.port}`}async stop(){this.log("stop: stopping server"),this.active=!1,this.log(`stop: detaching ${this.handlers.size} handlers`);for(let e of this.handlers)e.detach(!0);return this.handlers.clear(),this.server?new Promise(e=>{if(!this.server)return e();this.server.close(()=>{this.log("stop: server closed"),this.server=null,this.dispatchEvent(new CustomEvent("close")),e()})}):(this.log("stop: server not running, nothing to do"),Promise.resolve())}async handleConnection(e){let i={clientAddress:e.remoteAddress||"unknown",clientPort:e.remotePort||0};if(this.log(`handleConnection: new connection from ${i.clientAddress}:${i.clientPort}`),this.log(`handleConnection: active connections: ${this.handlers.size}, queued queries: ${this.queryQueue.getQueueLength()}`),!this.active){this.log("handleConnection: server not active, closing connection");try{e.end()}catch(r){this.log("handleConnection: error closing socket:",r)}return}if(this.handlers.size>=this.maxConnections){this.log("handleConnection: max connections reached, rejecting"),e.write(Buffer.from(`Too many connections
`)),e.end();return}let t=new d({queryQueue:this.queryQueue,closeOnDetach:!0,inspect:this.inspect,debug:this.debug,idleTimeout:this.idleTimeout});this.handlers.add(t),t.addEventListener("error",r=>{let o=r.detail;o?.message?.includes("ECONNRESET")?this.log(`handler #${t.handlerId}: client disconnected (ECONNRESET)`):o?.message?.includes("Idle timeout")?this.log(`handler #${t.handlerId}: idle timeout`):this.log(`handler #${t.handlerId}: error:`,o)}),t.addEventListener("close",()=>{this.log(`handler #${t.handlerId}: closed`),this.handlers.delete(t),this.log(`handleConnection: active connections: ${this.handlers.size}`)});try{await t.attach(e),this.dispatchEvent(new CustomEvent("connection",{detail:i}))}catch(r){this.log("handleConnection: error attaching socket:",r),this.handlers.delete(t),this.dispatchEvent(new CustomEvent("error",{detail:r}));try{e.end()}catch(o){this.log("handleConnection: error closing socket:",o)}}}getStats(){return{activeConnections:this.handlers.size,queuedQueries:this.queryQueue.getQueueLength(),maxConnections:this.maxConnections}}};export{b as a,d as b,u as c};
//# sourceMappingURL=chunk-NSUMFCRM.js.map
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { PGlite } from '@electric-sql/pglite'\nimport { type Server, type Socket, createServer } from 'net'\n\n// Connection queue timeout in milliseconds\nexport const CONNECTION_QUEUE_TIMEOUT = 60000 // 60 seconds\n\n/**\n * Represents a queued query waiting for PGlite access\n */\ninterface QueuedQuery {\n handlerId: number\n message: Uint8Array\n resolve: (resultSize: number) => void\n reject: (error: Error) => void\n timestamp: number\n onData: (data: Uint8Array) => void\n}\n\n/**\n * Global query queue manager\n * Ensures only one query executes at a time in PGlite\n */\nclass QueryQueueManager {\n private queue: QueuedQuery[] = []\n private processing = false\n private db: PGlite\n private debug: boolean\n private lastHandlerId: null | number = null\n\n constructor(db: PGlite, debug = false) {\n this.db = db\n this.debug = debug\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[QueryQueueManager] ${message}`, ...args)\n }\n }\n\n async enqueue(\n handlerId: number,\n message: Uint8Array,\n onData: (data: Uint8Array) => void,\n ): Promise<number> {\n return new Promise((resolve, reject) => {\n const query: QueuedQuery = {\n handlerId,\n message,\n resolve,\n reject,\n timestamp: Date.now(),\n onData,\n }\n\n this.queue.push(query)\n this.log(\n `enqueued query from handler #${handlerId}, queue size: ${this.queue.length}`,\n )\n\n // Process queue if not already processing\n if (!this.processing) {\n this.processQueue()\n }\n })\n }\n\n private async processQueue(): Promise<void> {\n if (this.processing || this.queue.length === 0) {\n return\n }\n\n this.processing = true\n\n while (this.queue.length > 0) {\n let query\n\n if (this.db.isInTransaction() && this.lastHandlerId) {\n const i = this.queue.findIndex(\n (q) => q.handlerId === this.lastHandlerId,\n )\n if (i === -1) {\n // we didn't find any other query from the same client!\n this.log(\n `transaction started, but no query from the same handler id found in queue`,\n this.lastHandlerId,\n )\n query = null\n } else {\n query = this.queue.splice(i, 1)[0]\n }\n } else {\n query = this.queue.shift()\n }\n if (!query) break\n\n const waitTime = Date.now() - query.timestamp\n this.log(\n `processing query from handler #${query.handlerId} (waited ${waitTime}ms)`,\n )\n\n let result = 0\n try {\n // Execute the query with exclusive access to PGlite\n await this.db.runExclusive(async () => {\n return await this.db.execProtocolRawStream(query.message, {\n onRawData: (data) => {\n result += data.length\n query.onData(data)\n },\n })\n })\n } catch (error) {\n this.log(`query from handler #${query.handlerId} failed:`, error)\n query.reject(error as Error)\n return\n }\n\n this.log(\n `query from handler #${query.handlerId} completed, ${result} bytes`,\n )\n this.lastHandlerId = query.handlerId\n query.resolve(result)\n }\n\n this.processing = false\n this.log(`queue processing complete, queue length is`, this.queue.length)\n }\n\n getQueueLength(): number {\n return this.queue.length\n }\n\n clearQueueForHandler(handlerId: number): void {\n const before = this.queue.length\n this.queue = this.queue.filter((q) => {\n if (q.handlerId === handlerId) {\n q.reject(new Error('Handler disconnected'))\n return false\n }\n return true\n })\n const removed = before - this.queue.length\n if (removed > 0) {\n this.log(`cleared ${removed} queries for handler #${handlerId}`)\n }\n }\n\n async clearTransactionIfNeeded(handlerId: number): Promise<void> {\n if (this.db.isInTransaction() && this.lastHandlerId === handlerId) {\n await this.db.exec('ROLLBACK')\n this.lastHandlerId = null\n await this.processQueue()\n }\n }\n}\n\n/**\n * Options for creating a PGLiteSocketHandler\n */\nexport interface PGLiteSocketHandlerOptions {\n /** The query queue manager */\n queryQueue: QueryQueueManager\n /** Whether to close the socket when detached (default: false) */\n closeOnDetach?: boolean\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n /** Idle timeout in ms (0 to disable, default: 0) */\n idleTimeout?: number\n}\n\n/**\n * Handler for a single socket connection to PGlite\n * Each connection can remain open and send multiple queries\n */\nexport class PGLiteSocketHandler extends EventTarget {\n private queryQueue: QueryQueueManager\n private socket: Socket | null = null\n private active = false\n private closeOnDetach: boolean\n private inspect: boolean\n private debug: boolean\n private readonly id: number\n private messageBuffer: Buffer = Buffer.alloc(0)\n private idleTimer?: NodeJS.Timeout\n private idleTimeout: number\n private lastActivityTime: number = Date.now()\n\n // Static counter for generating unique handler IDs\n private static nextHandlerId = 1\n\n constructor(options: PGLiteSocketHandlerOptions) {\n super()\n this.queryQueue = options.queryQueue\n this.closeOnDetach = options.closeOnDetach ?? false\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.idleTimeout = options.idleTimeout ?? 0\n this.id = PGLiteSocketHandler.nextHandlerId++\n\n this.log('constructor: created new handler')\n }\n\n public get handlerId(): number {\n return this.id\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketHandler#${this.id}] ${message}`, ...args)\n }\n }\n\n public async attach(socket: Socket): Promise<PGLiteSocketHandler> {\n this.log(\n `attach: attaching socket from ${socket.remoteAddress}:${socket.remotePort}`,\n )\n\n if (this.socket) {\n throw new Error('Socket already attached')\n }\n\n this.socket = socket\n this.active = true\n this.lastActivityTime = Date.now()\n\n // Set up socket options\n socket.setNoDelay(true)\n\n // Set up idle timeout if configured\n if (this.idleTimeout > 0) {\n this.resetIdleTimer()\n }\n\n // Setup event handlers\n this.log(`attach: setting up socket event handlers`)\n\n socket.on('data', (data) => {\n this.lastActivityTime = Date.now()\n this.resetIdleTimer()\n\n setImmediate(async () => {\n try {\n await this.handleData(data)\n } catch (err) {\n this.log('socket on data error: ', err)\n this.handleError(err as Error)\n }\n })\n })\n\n socket.on('error', (err) => {\n setImmediate(() => this.handleError(err))\n })\n\n socket.on('close', () => {\n setImmediate(() => this.handleClose())\n })\n\n this.log(`attach: socket handler ready`)\n return this\n }\n\n private resetIdleTimer(): void {\n if (this.idleTimeout <= 0) return\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n }\n\n this.idleTimer = setTimeout(() => {\n const idleTime = Date.now() - this.lastActivityTime\n this.log(`idle timeout after ${idleTime}ms`)\n this.handleError(new Error('Idle timeout'))\n }, this.idleTimeout)\n }\n\n public async detach(close?: boolean): Promise<PGLiteSocketHandler> {\n this.log(`detach: detaching socket, close=${close ?? this.closeOnDetach}`)\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n this.idleTimer = undefined\n }\n\n // Clear any pending queries for this handler\n this.queryQueue.clearQueueForHandler(this.id)\n\n await this.queryQueue.clearTransactionIfNeeded(this.id)\n\n if (!this.socket) {\n this.log(`detach: no socket attached, nothing to do`)\n return this\n }\n\n // Remove all listeners\n this.socket.removeAllListeners('data')\n this.socket.removeAllListeners('error')\n this.socket.removeAllListeners('close')\n\n // Close the socket if requested\n if (close ?? this.closeOnDetach) {\n if (this.socket.writable) {\n this.log(`detach: closing socket`)\n try {\n this.socket.end()\n this.socket.destroy()\n } catch (err) {\n this.log(`detach: error closing socket:`, err)\n }\n }\n }\n\n this.socket = null\n this.active = false\n this.messageBuffer = Buffer.alloc(0)\n\n this.log(`detach: handler cleaned up`)\n return this\n }\n\n public get isAttached(): boolean {\n return this.socket !== null\n }\n\n private async handleData(data: Buffer): Promise<number> {\n if (!this.socket || !this.active) {\n this.log(`handleData: no active socket, ignoring data`)\n return 0\n }\n\n this.log(`handleData: received ${data.length} bytes`)\n\n // Append to buffer for message reassembly\n this.messageBuffer = Buffer.concat([this.messageBuffer, data])\n\n // Print the incoming data to the console\n this.inspectData('incoming', data)\n\n try {\n let totalProcessed = 0\n\n while (this.messageBuffer.length > 0) {\n // Determine message length\n let messageLength = 0\n let isComplete = false\n\n // Handle startup message (no type byte, just length)\n if (this.messageBuffer.length >= 4) {\n const firstInt = this.messageBuffer.readInt32BE(0)\n\n if (this.messageBuffer.length >= 8) {\n const secondInt = this.messageBuffer.readInt32BE(4)\n // PostgreSQL 3.0 protocol version\n if (secondInt === 196608 || secondInt === 0x00030000) {\n messageLength = firstInt\n isComplete = this.messageBuffer.length >= messageLength\n }\n }\n\n // Regular message (type byte + length)\n if (!isComplete && this.messageBuffer.length >= 5) {\n const msgLength = this.messageBuffer.readInt32BE(1)\n messageLength = 1 + msgLength\n isComplete = this.messageBuffer.length >= messageLength\n }\n }\n\n if (!isComplete || messageLength === 0) {\n this.log(\n `handleData: incomplete message, buffering ${this.messageBuffer.length} bytes`,\n )\n break\n }\n\n // Extract and process complete message\n const message = this.messageBuffer.slice(0, messageLength)\n this.messageBuffer = this.messageBuffer.slice(messageLength)\n\n this.log(`handleData: processing message of ${message.length} bytes`)\n\n // Check if socket is still active before processing\n if (!this.active || !this.socket) {\n this.log(`handleData: socket no longer active, stopping processing`)\n break\n }\n\n let socketWriteError: any = undefined\n // Queue the query for execution\n // This allows multiple connections to queue queries simultaneously\n await this.queryQueue.enqueue(\n this.id,\n new Uint8Array(message),\n (data) => {\n this.log(`handleData: received ${data.length} bytes from PGlite`)\n\n // Print the outgoing data to the console\n this.inspectData('outgoing', data)\n\n // Send response if available\n if (\n data.length > 0 &&\n this.socket &&\n this.socket.writable &&\n this.active\n ) {\n // await new Promise<number>((resolve, reject) => {\n this.log(`handleData: writing response to socket`)\n if (this.socket?.writable) {\n this.socket.write(Buffer.from(data), (err?: any) => {\n if (err) {\n this.log(`handleData: error writing to socket:`, err)\n socketWriteError = err\n } else {\n this.log(`handleData: socket sent: ${data.length} bytes`)\n }\n })\n } else {\n this.log(`handleData: socket no longer writable`)\n }\n }\n totalProcessed += data.length\n },\n )\n if (socketWriteError) throw socketWriteError\n }\n\n // Emit data event with byte sizes\n this.dispatchEvent(\n new CustomEvent('data', {\n detail: { incoming: data.length, outgoing: totalProcessed },\n }),\n )\n\n return totalProcessed\n } catch (err) {\n this.log(`handleData: error processing data:`, err)\n throw err\n }\n }\n\n private handleError(err: Error): void {\n if (!this.active) {\n this.log(`handleError: handler not active, ignoring error`)\n return\n }\n\n // ECONNRESET is expected behavior when clients disconnect\n if (err.message?.includes('ECONNRESET')) {\n this.log(\n `handleError: client disconnected (ECONNRESET) - normal behavior`,\n )\n } else if (err.message?.includes('Idle timeout')) {\n this.log(`handleError: connection idle timeout`)\n } else {\n this.log(`handleError:`, err)\n }\n\n this.active = false\n\n // Emit error event\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n\n // Clean up\n this.detach(true)\n }\n\n private handleClose(): void {\n this.log(`handleClose: socket closed`)\n this.active = false\n this.dispatchEvent(new CustomEvent('close'))\n this.detach(false)\n }\n\n private inspectData(\n direction: 'incoming' | 'outgoing',\n data: Buffer | Uint8Array,\n ): void {\n if (!this.inspect) return\n console.log('-'.repeat(75))\n if (direction === 'incoming') {\n console.log('-> incoming', data.length, 'bytes')\n } else {\n console.log('<- outgoing', data.length, 'bytes')\n }\n\n for (let offset = 0; offset < data.length; offset += 16) {\n const chunkSize = Math.min(16, data.length - offset)\n\n let hexPart = ''\n for (let i = 0; i < 16; i++) {\n if (i < chunkSize) {\n const byte = data[offset + i]\n hexPart += byte.toString(16).padStart(2, '0') + ' '\n } else {\n hexPart += ' '\n }\n }\n\n let asciiPart = ''\n for (let i = 0; i < chunkSize; i++) {\n const byte = data[offset + i]\n asciiPart += byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : '.'\n }\n\n console.log(\n `${offset.toString(16).padStart(8, '0')} ${hexPart} ${asciiPart}`,\n )\n }\n }\n}\n\n/**\n * Options for creating a PGLiteSocketServer\n */\nexport interface PGLiteSocketServerOptions {\n /** The PGlite database instance */\n db: PGlite\n /** The port to listen on (default: 5432) */\n port?: number\n /** The host to bind to (default: 127.0.0.1) */\n host?: string\n /** Unix socket path to bind to (default: undefined) */\n path?: string\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n /** Idle timeout in ms (0 to disable, default: 0) */\n idleTimeout?: number\n /** Maximum concurrent connections (default: 100) */\n maxConnections?: number\n}\n\n/**\n * PGLite Socket Server with support for multiple concurrent connections\n * Connections remain open and queries are queued at the query level\n */\nexport class PGLiteSocketServer extends EventTarget {\n readonly db: PGlite\n private server: Server | null = null\n private port?: number\n private host?: string\n private path?: string\n private active = false\n private inspect: boolean\n private debug: boolean\n private idleTimeout: number\n private maxConnections: number\n private handlers: Set<PGLiteSocketHandler> = new Set()\n private queryQueue: QueryQueueManager\n\n constructor(options: PGLiteSocketServerOptions) {\n super()\n this.db = options.db\n if (options.path) {\n this.path = options.path\n } else {\n if (typeof options.port === 'number') {\n // Keep port undefined on port 0, will be set by the OS when we start the server.\n this.port = options.port ?? options.port\n } else {\n this.port = 5432\n }\n this.host = options.host || '127.0.0.1'\n }\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.idleTimeout = options.idleTimeout ?? 0\n this.maxConnections = options.maxConnections ?? 1\n\n // Create the shared query queue\n this.queryQueue = new QueryQueueManager(this.db, this.debug)\n\n this.log(`constructor: created server on ${this.getServerConn()}`)\n this.log(`constructor: max connections: ${this.maxConnections}`)\n if (this.idleTimeout > 0) {\n this.log(`constructor: idle timeout: ${this.idleTimeout}ms`)\n }\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketServer] ${message}`, ...args)\n }\n }\n\n public async start(): Promise<void> {\n this.log(`start: starting server on ${this.getServerConn()}`)\n\n if (this.server) {\n throw new Error('Socket server already started')\n }\n\n // Ensure PGlite is ready before accepting connections\n await this.db.waitReady\n\n this.active = true\n this.server = createServer((socket) => {\n setImmediate(() => this.handleConnection(socket))\n })\n\n this.server.maxConnections = this.maxConnections\n\n return new Promise<void>((resolve, reject) => {\n if (!this.server) return reject(new Error('Server not initialized'))\n\n this.server.on('error', (err) => {\n this.log(`start: server error:`, err)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n if (!this.active) {\n reject(err)\n }\n })\n\n if (this.path) {\n this.server.listen(this.path, () => {\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { path: this.path },\n }),\n )\n resolve()\n })\n } else {\n const server = this.server\n server.listen(this.port, this.host, () => {\n const address = server.address()\n // We are not using pipes, so return type should be AddressInfo\n if (address === null || typeof address !== 'object') {\n throw Error('Expected address info')\n }\n // Assign the new port number\n this.port = address.port\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { port: this.port, host: this.host },\n }),\n )\n resolve()\n })\n }\n })\n }\n\n public getServerConn(): string {\n if (this.path) return this.path\n return `${this.host}:${this.port}`\n }\n\n public async stop(): Promise<void> {\n this.log(`stop: stopping server`)\n\n this.active = false\n\n // Detach all handlers\n this.log(`stop: detaching ${this.handlers.size} handlers`)\n for (const handler of this.handlers) {\n handler.detach(true)\n }\n this.handlers.clear()\n\n if (!this.server) {\n this.log(`stop: server not running, nothing to do`)\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve) => {\n if (!this.server) return resolve()\n\n this.server.close(() => {\n this.log(`stop: server closed`)\n this.server = null\n this.dispatchEvent(new CustomEvent('close'))\n resolve()\n })\n })\n }\n\n private async handleConnection(socket: Socket): Promise<void> {\n const clientInfo = {\n clientAddress: socket.remoteAddress || 'unknown',\n clientPort: socket.remotePort || 0,\n }\n\n this.log(\n `handleConnection: new connection from ${clientInfo.clientAddress}:${clientInfo.clientPort}`,\n )\n this.log(\n `handleConnection: active connections: ${this.handlers.size}, queued queries: ${this.queryQueue.getQueueLength()}`,\n )\n\n if (!this.active) {\n this.log(`handleConnection: server not active, closing connection`)\n try {\n socket.end()\n } catch (err) {\n this.log(`handleConnection: error closing socket:`, err)\n }\n return\n }\n\n // Check connection limit\n if (this.handlers.size >= this.maxConnections) {\n this.log(`handleConnection: max connections reached, rejecting`)\n socket.write(Buffer.from('Too many connections\\n'))\n socket.end()\n return\n }\n\n // Create a new handler for this connection\n const handler = new PGLiteSocketHandler({\n queryQueue: this.queryQueue,\n closeOnDetach: true,\n inspect: this.inspect,\n debug: this.debug,\n idleTimeout: this.idleTimeout,\n })\n\n // Track this handler\n this.handlers.add(handler)\n\n // Handle errors\n handler.addEventListener('error', (event) => {\n const error = (event as CustomEvent<Error>).detail\n\n if (error?.message?.includes('ECONNRESET')) {\n this.log(\n `handler #${handler.handlerId}: client disconnected (ECONNRESET)`,\n )\n } else if (error?.message?.includes('Idle timeout')) {\n this.log(`handler #${handler.handlerId}: idle timeout`)\n } else {\n this.log(`handler #${handler.handlerId}: error:`, error)\n }\n })\n\n // Handle close event\n handler.addEventListener('close', () => {\n this.log(`handler #${handler.handlerId}: closed`)\n this.handlers.delete(handler)\n this.log(`handleConnection: active connections: ${this.handlers.size}`)\n })\n\n try {\n await handler.attach(socket)\n this.dispatchEvent(new CustomEvent('connection', { detail: clientInfo }))\n } catch (err) {\n this.log(`handleConnection: error attaching socket:`, err)\n this.handlers.delete(handler)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n try {\n socket.end()\n } catch (closeErr) {\n this.log(`handleConnection: error closing socket:`, closeErr)\n }\n }\n }\n\n public getStats() {\n return {\n activeConnections: this.handlers.size,\n queuedQueries: this.queryQueue.getQueueLength(),\n maxConnections: this.maxConnections,\n }\n }\n}\n"],"mappings":"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","names":["createServer","CONNECTION_QUEUE_TIMEOUT","QueryQueueManager","db","debug","message","args","handlerId","onData","resolve","reject","query","i","q","waitTime","result","data","error","before","removed","_PGLiteSocketHandler","options","socket","err","idleTime","close","totalProcessed","messageLength","isComplete","firstInt","secondInt","socketWriteError","direction","offset","chunkSize","hexPart","byte","asciiPart","PGLiteSocketHandler","PGLiteSocketServer","server","address","handler","clientInfo","event","closeErr"]}
+8
-0
# @electric-sql/pglite-socket
## 0.1.0
### Minor Changes
- Updated dependencies [d848955]
- @electric-sql/pglite-postgis@0.0.1
- @electric-sql/pglite@0.4.0
## 0.0.22

@@ -4,0 +12,0 @@

+1
-1

@@ -1,3 +0,3 @@

"use strict";var g=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var E=(l,s)=>{for(var e in s)g(l,e,{get:s[e],enumerable:!0})},w=(l,s,e,i)=>{if(s&&typeof s=="object"||typeof s=="function")for(let t of b(s))!y.call(l,t)&&t!==e&&g(l,t,{get:()=>s[t],enumerable:!(i=p(s,t))||i.enumerable});return l};var C=l=>w(g({},"__esModule",{value:!0}),l);var q={};E(q,{CONNECTION_QUEUE_TIMEOUT:()=>T,PGLiteSocketHandler:()=>c,PGLiteSocketServer:()=>f});module.exports=C(q);var v=require("net"),T=6e4,m=class{constructor(s,e=!1){this.queue=[];this.processing=!1;this.lastHandlerId=null;this.db=s,this.debug=e}log(s,...e){this.debug&&console.log(`[QueryQueueManager] ${s}`,...e)}async enqueue(s,e){return new Promise((i,t)=>{let r={handlerId:s,message:e,resolve:i,reject:t,timestamp:Date.now()};this.queue.push(r),this.log(`enqueued query from handler #${s}, queue size: ${this.queue.length}`),this.processing||this.processQueue()})}async processQueue(){if(!(this.processing||this.queue.length===0)){for(this.processing=!0;this.queue.length>0;){let s;if(this.db.isInTransaction()&&this.lastHandlerId){let i=this.queue.findIndex(t=>t.handlerId===this.lastHandlerId);i===-1?(this.log("transaction started, but no query from the same handler id found in queue",this.lastHandlerId),s=null):s=this.queue.splice(i,1)[0]}else s=this.queue.shift();if(!s)break;let e=Date.now()-s.timestamp;this.log(`processing query from handler #${s.handlerId} (waited ${e}ms)`);try{let i=await this.db.runExclusive(async()=>await this.db.execProtocolRaw(s.message));this.log(`query from handler #${s.handlerId} completed, ${i.length} bytes`),this.lastHandlerId=s.handlerId,s.resolve(i)}catch(i){this.log(`query from handler #${s.handlerId} failed:`,i),s.reject(i)}}this.processing=!1,this.log("queue processing complete, queue length is",this.queue.length)}}getQueueLength(){return this.queue.length}clearQueueForHandler(s){let e=this.queue.length;this.queue=this.queue.filter(t=>t.handlerId===s?(t.reject(new Error("Handler disconnected")),!1):!0);let i=e-this.queue.length;i>0&&this.log(`cleared ${i} queries for handler #${s}`)}async clearTransactionIfNeeded(s){this.db.isInTransaction()&&this.lastHandlerId===s&&(await this.db.exec("ROLLBACK"),this.lastHandlerId=null,await this.processQueue())}},d=class d extends EventTarget{constructor(e){super();this.socket=null;this.active=!1;this.messageBuffer=Buffer.alloc(0);this.lastActivityTime=Date.now();this.queryQueue=e.queryQueue,this.closeOnDetach=e.closeOnDetach??!1,this.inspect=e.inspect??!1,this.debug=e.debug??!1,this.idleTimeout=e.idleTimeout??0,this.id=d.nextHandlerId++,this.log("constructor: created new handler")}get handlerId(){return this.id}log(e,...i){this.debug&&console.log(`[PGLiteSocketHandler#${this.id}] ${e}`,...i)}async attach(e){if(this.log(`attach: attaching socket from ${e.remoteAddress}:${e.remotePort}`),this.socket)throw new Error("Socket already attached");return this.socket=e,this.active=!0,this.lastActivityTime=Date.now(),e.setNoDelay(!0),this.idleTimeout>0&&this.resetIdleTimer(),this.log("attach: setting up socket event handlers"),e.on("data",i=>{this.lastActivityTime=Date.now(),this.resetIdleTimer(),setImmediate(async()=>{try{await this.handleData(i)}catch(t){this.log("socket on data error: ",t),this.handleError(t)}})}),e.on("error",i=>{setImmediate(()=>this.handleError(i))}),e.on("close",()=>{setImmediate(()=>this.handleClose())}),this.log("attach: socket handler ready"),this}resetIdleTimer(){this.idleTimeout<=0||(this.idleTimer&&clearTimeout(this.idleTimer),this.idleTimer=setTimeout(()=>{let e=Date.now()-this.lastActivityTime;this.log(`idle timeout after ${e}ms`),this.handleError(new Error("Idle timeout"))},this.idleTimeout))}async detach(e){if(this.log(`detach: detaching socket, close=${e??this.closeOnDetach}`),this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=void 0),this.queryQueue.clearQueueForHandler(this.id),await this.queryQueue.clearTransactionIfNeeded(this.id),!this.socket)return this.log("detach: no socket attached, nothing to do"),this;if(this.socket.removeAllListeners("data"),this.socket.removeAllListeners("error"),this.socket.removeAllListeners("close"),(e??this.closeOnDetach)&&this.socket.writable){this.log("detach: closing socket");try{this.socket.end(),this.socket.destroy()}catch(i){this.log("detach: error closing socket:",i)}}return this.socket=null,this.active=!1,this.messageBuffer=Buffer.alloc(0),this.log("detach: handler cleaned up"),this}get isAttached(){return this.socket!==null}async handleData(e){if(!this.socket||!this.active)return this.log("handleData: no active socket, ignoring data"),0;this.log(`handleData: received ${e.length} bytes`),this.messageBuffer=Buffer.concat([this.messageBuffer,e]),this.inspectData("incoming",e);try{let i=0;for(;this.messageBuffer.length>0;){let t=0,r=!1;if(this.messageBuffer.length>=4){let n=this.messageBuffer.readInt32BE(0);if(this.messageBuffer.length>=8){let a=this.messageBuffer.readInt32BE(4);(a===196608||a===196608)&&(t=n,r=this.messageBuffer.length>=t)}!r&&this.messageBuffer.length>=5&&(t=1+this.messageBuffer.readInt32BE(1),r=this.messageBuffer.length>=t)}if(!r||t===0){this.log(`handleData: incomplete message, buffering ${this.messageBuffer.length} bytes`);break}let o=this.messageBuffer.slice(0,t);if(this.messageBuffer=this.messageBuffer.slice(t),this.log(`handleData: processing message of ${o.length} bytes`),!this.active||!this.socket){this.log("handleData: socket no longer active, stopping processing");break}let h=await this.queryQueue.enqueue(this.id,new Uint8Array(o));this.log(`handleData: received ${h.length} bytes from PGlite`),this.inspectData("outgoing",h),h.length>0&&this.socket&&this.socket.writable&&this.active&&await new Promise((n,a)=>{this.log("handleData: writing response to socket"),this.socket?.writable?this.socket.write(Buffer.from(h),u=>{u?(this.log("handleData: error writing to socket:",u),a(u)):(this.log(`handleData: socket sent: ${h.length} bytes`),n(h.length))}):(this.log("handleData: socket no longer writable"),n(0))}).catch(n=>{throw this.log("handleData: failed to write to socket:",n),n}),i+=h.length}return this.dispatchEvent(new CustomEvent("data",{detail:{incoming:e.length,outgoing:i}})),i}catch(i){throw this.log("handleData: error processing data:",i),i}}handleError(e){if(!this.active){this.log("handleError: handler not active, ignoring error");return}e.message?.includes("ECONNRESET")?this.log("handleError: client disconnected (ECONNRESET) - normal behavior"):e.message?.includes("Idle timeout")?this.log("handleError: connection idle timeout"):this.log("handleError:",e),this.active=!1,this.dispatchEvent(new CustomEvent("error",{detail:e})),this.detach(!0)}handleClose(){this.log("handleClose: socket closed"),this.active=!1,this.dispatchEvent(new CustomEvent("close")),this.detach(!1)}inspectData(e,i){if(this.inspect){console.log("-".repeat(75)),console.log(e==="incoming"?"-> incoming":"<- outgoing",i.length,"bytes");for(let t=0;t<i.length;t+=16){let r=Math.min(16,i.length-t),o="";for(let n=0;n<16;n++)if(n<r){let a=i[t+n];o+=a.toString(16).padStart(2,"0")+" "}else o+=" ";let h="";for(let n=0;n<r;n++){let a=i[t+n];h+=a>=32&&a<=126?String.fromCharCode(a):"."}console.log(`${t.toString(16).padStart(8,"0")} ${o} ${h}`)}}}};d.nextHandlerId=1;var c=d,f=class extends EventTarget{constructor(e){super();this.server=null;this.active=!1;this.handlers=new Set;this.db=e.db,e.path?this.path=e.path:(typeof e.port=="number"?this.port=e.port??e.port:this.port=5432,this.host=e.host||"127.0.0.1"),this.inspect=e.inspect??!1,this.debug=e.debug??!1,this.idleTimeout=e.idleTimeout??0,this.maxConnections=e.maxConnections??1,this.queryQueue=new m(this.db,this.debug),this.log(`constructor: created server on ${this.getServerConn()}`),this.log(`constructor: max connections: ${this.maxConnections}`),this.idleTimeout>0&&this.log(`constructor: idle timeout: ${this.idleTimeout}ms`)}log(e,...i){this.debug&&console.log(`[PGLiteSocketServer] ${e}`,...i)}async start(){if(this.log(`start: starting server on ${this.getServerConn()}`),this.server)throw new Error("Socket server already started");return await this.db.waitReady,this.active=!0,this.server=(0,v.createServer)(e=>{setImmediate(()=>this.handleConnection(e))}),this.server.maxConnections=this.maxConnections,new Promise((e,i)=>{if(!this.server)return i(new Error("Server not initialized"));if(this.server.on("error",t=>{this.log("start: server error:",t),this.dispatchEvent(new CustomEvent("error",{detail:t})),this.active||i(t)}),this.path)this.server.listen(this.path,()=>{this.log(`start: server listening on ${this.getServerConn()}`),this.dispatchEvent(new CustomEvent("listening",{detail:{path:this.path}})),e()});else{let t=this.server;t.listen(this.port,this.host,()=>{let r=t.address();if(r===null||typeof r!="object")throw Error("Expected address info");this.port=r.port,this.log(`start: server listening on ${this.getServerConn()}`),this.dispatchEvent(new CustomEvent("listening",{detail:{port:this.port,host:this.host}})),e()})}})}getServerConn(){return this.path?this.path:`${this.host}:${this.port}`}async stop(){this.log("stop: stopping server"),this.active=!1,this.log(`stop: detaching ${this.handlers.size} handlers`);for(let e of this.handlers)e.detach(!0);return this.handlers.clear(),this.server?new Promise(e=>{if(!this.server)return e();this.server.close(()=>{this.log("stop: server closed"),this.server=null,this.dispatchEvent(new CustomEvent("close")),e()})}):(this.log("stop: server not running, nothing to do"),Promise.resolve())}async handleConnection(e){let i={clientAddress:e.remoteAddress||"unknown",clientPort:e.remotePort||0};if(this.log(`handleConnection: new connection from ${i.clientAddress}:${i.clientPort}`),this.log(`handleConnection: active connections: ${this.handlers.size}, queued queries: ${this.queryQueue.getQueueLength()}`),!this.active){this.log("handleConnection: server not active, closing connection");try{e.end()}catch(r){this.log("handleConnection: error closing socket:",r)}return}if(this.handlers.size>=this.maxConnections){this.log("handleConnection: max connections reached, rejecting"),e.write(Buffer.from(`Too many connections
"use strict";var u=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var y=(h,s)=>{for(var e in s)u(h,e,{get:s[e],enumerable:!0})},E=(h,s,e,i)=>{if(s&&typeof s=="object"||typeof s=="function")for(let t of p(s))!b.call(h,t)&&t!==e&&u(h,t,{get:()=>s[t],enumerable:!(i=v(s,t))||i.enumerable});return h};var w=h=>E(u({},"__esModule",{value:!0}),h);var T={};y(T,{CONNECTION_QUEUE_TIMEOUT:()=>C,PGLiteSocketHandler:()=>c,PGLiteSocketServer:()=>m});module.exports=w(T);var f=require("net"),C=6e4,g=class{constructor(s,e=!1){this.queue=[];this.processing=!1;this.lastHandlerId=null;this.db=s,this.debug=e}log(s,...e){this.debug&&console.log(`[QueryQueueManager] ${s}`,...e)}async enqueue(s,e,i){return new Promise((t,r)=>{let o={handlerId:s,message:e,resolve:t,reject:r,timestamp:Date.now(),onData:i};this.queue.push(o),this.log(`enqueued query from handler #${s}, queue size: ${this.queue.length}`),this.processing||this.processQueue()})}async processQueue(){if(!(this.processing||this.queue.length===0)){for(this.processing=!0;this.queue.length>0;){let s;if(this.db.isInTransaction()&&this.lastHandlerId){let t=this.queue.findIndex(r=>r.handlerId===this.lastHandlerId);t===-1?(this.log("transaction started, but no query from the same handler id found in queue",this.lastHandlerId),s=null):s=this.queue.splice(t,1)[0]}else s=this.queue.shift();if(!s)break;let e=Date.now()-s.timestamp;this.log(`processing query from handler #${s.handlerId} (waited ${e}ms)`);let i=0;try{await this.db.runExclusive(async()=>await this.db.execProtocolRawStream(s.message,{onRawData:t=>{i+=t.length,s.onData(t)}}))}catch(t){this.log(`query from handler #${s.handlerId} failed:`,t),s.reject(t);return}this.log(`query from handler #${s.handlerId} completed, ${i} bytes`),this.lastHandlerId=s.handlerId,s.resolve(i)}this.processing=!1,this.log("queue processing complete, queue length is",this.queue.length)}}getQueueLength(){return this.queue.length}clearQueueForHandler(s){let e=this.queue.length;this.queue=this.queue.filter(t=>t.handlerId===s?(t.reject(new Error("Handler disconnected")),!1):!0);let i=e-this.queue.length;i>0&&this.log(`cleared ${i} queries for handler #${s}`)}async clearTransactionIfNeeded(s){this.db.isInTransaction()&&this.lastHandlerId===s&&(await this.db.exec("ROLLBACK"),this.lastHandlerId=null,await this.processQueue())}},d=class d extends EventTarget{constructor(e){super();this.socket=null;this.active=!1;this.messageBuffer=Buffer.alloc(0);this.lastActivityTime=Date.now();this.queryQueue=e.queryQueue,this.closeOnDetach=e.closeOnDetach??!1,this.inspect=e.inspect??!1,this.debug=e.debug??!1,this.idleTimeout=e.idleTimeout??0,this.id=d.nextHandlerId++,this.log("constructor: created new handler")}get handlerId(){return this.id}log(e,...i){this.debug&&console.log(`[PGLiteSocketHandler#${this.id}] ${e}`,...i)}async attach(e){if(this.log(`attach: attaching socket from ${e.remoteAddress}:${e.remotePort}`),this.socket)throw new Error("Socket already attached");return this.socket=e,this.active=!0,this.lastActivityTime=Date.now(),e.setNoDelay(!0),this.idleTimeout>0&&this.resetIdleTimer(),this.log("attach: setting up socket event handlers"),e.on("data",i=>{this.lastActivityTime=Date.now(),this.resetIdleTimer(),setImmediate(async()=>{try{await this.handleData(i)}catch(t){this.log("socket on data error: ",t),this.handleError(t)}})}),e.on("error",i=>{setImmediate(()=>this.handleError(i))}),e.on("close",()=>{setImmediate(()=>this.handleClose())}),this.log("attach: socket handler ready"),this}resetIdleTimer(){this.idleTimeout<=0||(this.idleTimer&&clearTimeout(this.idleTimer),this.idleTimer=setTimeout(()=>{let e=Date.now()-this.lastActivityTime;this.log(`idle timeout after ${e}ms`),this.handleError(new Error("Idle timeout"))},this.idleTimeout))}async detach(e){if(this.log(`detach: detaching socket, close=${e??this.closeOnDetach}`),this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=void 0),this.queryQueue.clearQueueForHandler(this.id),await this.queryQueue.clearTransactionIfNeeded(this.id),!this.socket)return this.log("detach: no socket attached, nothing to do"),this;if(this.socket.removeAllListeners("data"),this.socket.removeAllListeners("error"),this.socket.removeAllListeners("close"),(e??this.closeOnDetach)&&this.socket.writable){this.log("detach: closing socket");try{this.socket.end(),this.socket.destroy()}catch(i){this.log("detach: error closing socket:",i)}}return this.socket=null,this.active=!1,this.messageBuffer=Buffer.alloc(0),this.log("detach: handler cleaned up"),this}get isAttached(){return this.socket!==null}async handleData(e){if(!this.socket||!this.active)return this.log("handleData: no active socket, ignoring data"),0;this.log(`handleData: received ${e.length} bytes`),this.messageBuffer=Buffer.concat([this.messageBuffer,e]),this.inspectData("incoming",e);try{let i=0;for(;this.messageBuffer.length>0;){let t=0,r=!1;if(this.messageBuffer.length>=4){let n=this.messageBuffer.readInt32BE(0);if(this.messageBuffer.length>=8){let a=this.messageBuffer.readInt32BE(4);(a===196608||a===196608)&&(t=n,r=this.messageBuffer.length>=t)}!r&&this.messageBuffer.length>=5&&(t=1+this.messageBuffer.readInt32BE(1),r=this.messageBuffer.length>=t)}if(!r||t===0){this.log(`handleData: incomplete message, buffering ${this.messageBuffer.length} bytes`);break}let o=this.messageBuffer.slice(0,t);if(this.messageBuffer=this.messageBuffer.slice(t),this.log(`handleData: processing message of ${o.length} bytes`),!this.active||!this.socket){this.log("handleData: socket no longer active, stopping processing");break}let l;if(await this.queryQueue.enqueue(this.id,new Uint8Array(o),n=>{this.log(`handleData: received ${n.length} bytes from PGlite`),this.inspectData("outgoing",n),n.length>0&&this.socket&&this.socket.writable&&this.active&&(this.log("handleData: writing response to socket"),this.socket?.writable?this.socket.write(Buffer.from(n),a=>{a?(this.log("handleData: error writing to socket:",a),l=a):this.log(`handleData: socket sent: ${n.length} bytes`)}):this.log("handleData: socket no longer writable")),i+=n.length}),l)throw l}return this.dispatchEvent(new CustomEvent("data",{detail:{incoming:e.length,outgoing:i}})),i}catch(i){throw this.log("handleData: error processing data:",i),i}}handleError(e){if(!this.active){this.log("handleError: handler not active, ignoring error");return}e.message?.includes("ECONNRESET")?this.log("handleError: client disconnected (ECONNRESET) - normal behavior"):e.message?.includes("Idle timeout")?this.log("handleError: connection idle timeout"):this.log("handleError:",e),this.active=!1,this.dispatchEvent(new CustomEvent("error",{detail:e})),this.detach(!0)}handleClose(){this.log("handleClose: socket closed"),this.active=!1,this.dispatchEvent(new CustomEvent("close")),this.detach(!1)}inspectData(e,i){if(this.inspect){console.log("-".repeat(75)),console.log(e==="incoming"?"-> incoming":"<- outgoing",i.length,"bytes");for(let t=0;t<i.length;t+=16){let r=Math.min(16,i.length-t),o="";for(let n=0;n<16;n++)if(n<r){let a=i[t+n];o+=a.toString(16).padStart(2,"0")+" "}else o+=" ";let l="";for(let n=0;n<r;n++){let a=i[t+n];l+=a>=32&&a<=126?String.fromCharCode(a):"."}console.log(`${t.toString(16).padStart(8,"0")} ${o} ${l}`)}}}};d.nextHandlerId=1;var c=d,m=class extends EventTarget{constructor(e){super();this.server=null;this.active=!1;this.handlers=new Set;this.db=e.db,e.path?this.path=e.path:(typeof e.port=="number"?this.port=e.port??e.port:this.port=5432,this.host=e.host||"127.0.0.1"),this.inspect=e.inspect??!1,this.debug=e.debug??!1,this.idleTimeout=e.idleTimeout??0,this.maxConnections=e.maxConnections??1,this.queryQueue=new g(this.db,this.debug),this.log(`constructor: created server on ${this.getServerConn()}`),this.log(`constructor: max connections: ${this.maxConnections}`),this.idleTimeout>0&&this.log(`constructor: idle timeout: ${this.idleTimeout}ms`)}log(e,...i){this.debug&&console.log(`[PGLiteSocketServer] ${e}`,...i)}async start(){if(this.log(`start: starting server on ${this.getServerConn()}`),this.server)throw new Error("Socket server already started");return await this.db.waitReady,this.active=!0,this.server=(0,f.createServer)(e=>{setImmediate(()=>this.handleConnection(e))}),this.server.maxConnections=this.maxConnections,new Promise((e,i)=>{if(!this.server)return i(new Error("Server not initialized"));if(this.server.on("error",t=>{this.log("start: server error:",t),this.dispatchEvent(new CustomEvent("error",{detail:t})),this.active||i(t)}),this.path)this.server.listen(this.path,()=>{this.log(`start: server listening on ${this.getServerConn()}`),this.dispatchEvent(new CustomEvent("listening",{detail:{path:this.path}})),e()});else{let t=this.server;t.listen(this.port,this.host,()=>{let r=t.address();if(r===null||typeof r!="object")throw Error("Expected address info");this.port=r.port,this.log(`start: server listening on ${this.getServerConn()}`),this.dispatchEvent(new CustomEvent("listening",{detail:{port:this.port,host:this.host}})),e()})}})}getServerConn(){return this.path?this.path:`${this.host}:${this.port}`}async stop(){this.log("stop: stopping server"),this.active=!1,this.log(`stop: detaching ${this.handlers.size} handlers`);for(let e of this.handlers)e.detach(!0);return this.handlers.clear(),this.server?new Promise(e=>{if(!this.server)return e();this.server.close(()=>{this.log("stop: server closed"),this.server=null,this.dispatchEvent(new CustomEvent("close")),e()})}):(this.log("stop: server not running, nothing to do"),Promise.resolve())}async handleConnection(e){let i={clientAddress:e.remoteAddress||"unknown",clientPort:e.remotePort||0};if(this.log(`handleConnection: new connection from ${i.clientAddress}:${i.clientPort}`),this.log(`handleConnection: active connections: ${this.handlers.size}, queued queries: ${this.queryQueue.getQueueLength()}`),!this.active){this.log("handleConnection: server not active, closing connection");try{e.end()}catch(r){this.log("handleConnection: error closing socket:",r)}return}if(this.handlers.size>=this.maxConnections){this.log("handleConnection: max connections reached, rejecting"),e.write(Buffer.from(`Too many connections
`)),e.end();return}let t=new c({queryQueue:this.queryQueue,closeOnDetach:!0,inspect:this.inspect,debug:this.debug,idleTimeout:this.idleTimeout});this.handlers.add(t),t.addEventListener("error",r=>{let o=r.detail;o?.message?.includes("ECONNRESET")?this.log(`handler #${t.handlerId}: client disconnected (ECONNRESET)`):o?.message?.includes("Idle timeout")?this.log(`handler #${t.handlerId}: idle timeout`):this.log(`handler #${t.handlerId}: error:`,o)}),t.addEventListener("close",()=>{this.log(`handler #${t.handlerId}: closed`),this.handlers.delete(t),this.log(`handleConnection: active connections: ${this.handlers.size}`)});try{await t.attach(e),this.dispatchEvent(new CustomEvent("connection",{detail:i}))}catch(r){this.log("handleConnection: error attaching socket:",r),this.handlers.delete(t),this.dispatchEvent(new CustomEvent("error",{detail:r}));try{e.end()}catch(o){this.log("handleConnection: error closing socket:",o)}}}getStats(){return{activeConnections:this.handlers.size,queuedQueries:this.queryQueue.getQueueLength(),maxConnections:this.maxConnections}}};0&&(module.exports={CONNECTION_QUEUE_TIMEOUT,PGLiteSocketHandler,PGLiteSocketServer});
//# sourceMappingURL=index.cjs.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { PGlite } from '@electric-sql/pglite'\nimport { type Server, type Socket, createServer } from 'net'\n\n// Connection queue timeout in milliseconds\nexport const CONNECTION_QUEUE_TIMEOUT = 60000 // 60 seconds\n\n/**\n * Represents a queued query waiting for PGlite access\n */\ninterface QueuedQuery {\n handlerId: number\n message: Uint8Array\n resolve: (result: Uint8Array) => void\n reject: (error: Error) => void\n timestamp: number\n}\n\n/**\n * Global query queue manager\n * Ensures only one query executes at a time in PGlite\n */\nclass QueryQueueManager {\n private queue: QueuedQuery[] = []\n private processing = false\n private db: PGlite\n private debug: boolean\n private lastHandlerId: null | number = null\n\n constructor(db: PGlite, debug = false) {\n this.db = db\n this.debug = debug\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[QueryQueueManager] ${message}`, ...args)\n }\n }\n\n async enqueue(handlerId: number, message: Uint8Array): Promise<Uint8Array> {\n return new Promise((resolve, reject) => {\n const query: QueuedQuery = {\n handlerId,\n message,\n resolve,\n reject,\n timestamp: Date.now(),\n }\n\n this.queue.push(query)\n this.log(\n `enqueued query from handler #${handlerId}, queue size: ${this.queue.length}`,\n )\n\n // Process queue if not already processing\n if (!this.processing) {\n this.processQueue()\n }\n })\n }\n\n private async processQueue(): Promise<void> {\n if (this.processing || this.queue.length === 0) {\n return\n }\n\n this.processing = true\n\n while (this.queue.length > 0) {\n let query\n\n if (this.db.isInTransaction() && this.lastHandlerId) {\n const i = this.queue.findIndex(\n (q) => q.handlerId === this.lastHandlerId,\n )\n if (i === -1) {\n // we didn't find any other query from the same client!\n this.log(\n `transaction started, but no query from the same handler id found in queue`,\n this.lastHandlerId,\n )\n query = null\n } else {\n query = this.queue.splice(i, 1)[0]\n }\n } else {\n query = this.queue.shift()\n }\n if (!query) break\n\n const waitTime = Date.now() - query.timestamp\n this.log(\n `processing query from handler #${query.handlerId} (waited ${waitTime}ms)`,\n )\n\n try {\n // Execute the query with exclusive access to PGlite\n const result = await this.db.runExclusive(async () => {\n return await this.db.execProtocolRaw(query.message)\n })\n\n this.log(\n `query from handler #${query.handlerId} completed, ${result.length} bytes`,\n )\n this.lastHandlerId = query.handlerId\n query.resolve(result)\n } catch (error) {\n this.log(`query from handler #${query.handlerId} failed:`, error)\n query.reject(error as Error)\n }\n }\n\n this.processing = false\n this.log(`queue processing complete, queue length is`, this.queue.length)\n }\n\n getQueueLength(): number {\n return this.queue.length\n }\n\n clearQueueForHandler(handlerId: number): void {\n const before = this.queue.length\n this.queue = this.queue.filter((q) => {\n if (q.handlerId === handlerId) {\n q.reject(new Error('Handler disconnected'))\n return false\n }\n return true\n })\n const removed = before - this.queue.length\n if (removed > 0) {\n this.log(`cleared ${removed} queries for handler #${handlerId}`)\n }\n }\n\n async clearTransactionIfNeeded(handlerId: number): Promise<void> {\n if (this.db.isInTransaction() && this.lastHandlerId === handlerId) {\n await this.db.exec('ROLLBACK')\n this.lastHandlerId = null\n await this.processQueue()\n }\n }\n}\n\n/**\n * Options for creating a PGLiteSocketHandler\n */\nexport interface PGLiteSocketHandlerOptions {\n /** The query queue manager */\n queryQueue: QueryQueueManager\n /** Whether to close the socket when detached (default: false) */\n closeOnDetach?: boolean\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n /** Idle timeout in ms (0 to disable, default: 0) */\n idleTimeout?: number\n}\n\n/**\n * Handler for a single socket connection to PGlite\n * Each connection can remain open and send multiple queries\n */\nexport class PGLiteSocketHandler extends EventTarget {\n private queryQueue: QueryQueueManager\n private socket: Socket | null = null\n private active = false\n private closeOnDetach: boolean\n private inspect: boolean\n private debug: boolean\n private readonly id: number\n private messageBuffer: Buffer = Buffer.alloc(0)\n private idleTimer?: NodeJS.Timeout\n private idleTimeout: number\n private lastActivityTime: number = Date.now()\n\n // Static counter for generating unique handler IDs\n private static nextHandlerId = 1\n\n constructor(options: PGLiteSocketHandlerOptions) {\n super()\n this.queryQueue = options.queryQueue\n this.closeOnDetach = options.closeOnDetach ?? false\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.idleTimeout = options.idleTimeout ?? 0\n this.id = PGLiteSocketHandler.nextHandlerId++\n\n this.log('constructor: created new handler')\n }\n\n public get handlerId(): number {\n return this.id\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketHandler#${this.id}] ${message}`, ...args)\n }\n }\n\n public async attach(socket: Socket): Promise<PGLiteSocketHandler> {\n this.log(\n `attach: attaching socket from ${socket.remoteAddress}:${socket.remotePort}`,\n )\n\n if (this.socket) {\n throw new Error('Socket already attached')\n }\n\n this.socket = socket\n this.active = true\n this.lastActivityTime = Date.now()\n\n // Set up socket options\n socket.setNoDelay(true)\n\n // Set up idle timeout if configured\n if (this.idleTimeout > 0) {\n this.resetIdleTimer()\n }\n\n // Setup event handlers\n this.log(`attach: setting up socket event handlers`)\n\n socket.on('data', (data) => {\n this.lastActivityTime = Date.now()\n this.resetIdleTimer()\n\n setImmediate(async () => {\n try {\n await this.handleData(data)\n } catch (err) {\n this.log('socket on data error: ', err)\n this.handleError(err as Error)\n }\n })\n })\n\n socket.on('error', (err) => {\n setImmediate(() => this.handleError(err))\n })\n\n socket.on('close', () => {\n setImmediate(() => this.handleClose())\n })\n\n this.log(`attach: socket handler ready`)\n return this\n }\n\n private resetIdleTimer(): void {\n if (this.idleTimeout <= 0) return\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n }\n\n this.idleTimer = setTimeout(() => {\n const idleTime = Date.now() - this.lastActivityTime\n this.log(`idle timeout after ${idleTime}ms`)\n this.handleError(new Error('Idle timeout'))\n }, this.idleTimeout)\n }\n\n public async detach(close?: boolean): Promise<PGLiteSocketHandler> {\n this.log(`detach: detaching socket, close=${close ?? this.closeOnDetach}`)\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n this.idleTimer = undefined\n }\n\n // Clear any pending queries for this handler\n this.queryQueue.clearQueueForHandler(this.id)\n\n await this.queryQueue.clearTransactionIfNeeded(this.id)\n\n if (!this.socket) {\n this.log(`detach: no socket attached, nothing to do`)\n return this\n }\n\n // Remove all listeners\n this.socket.removeAllListeners('data')\n this.socket.removeAllListeners('error')\n this.socket.removeAllListeners('close')\n\n // Close the socket if requested\n if (close ?? this.closeOnDetach) {\n if (this.socket.writable) {\n this.log(`detach: closing socket`)\n try {\n this.socket.end()\n this.socket.destroy()\n } catch (err) {\n this.log(`detach: error closing socket:`, err)\n }\n }\n }\n\n this.socket = null\n this.active = false\n this.messageBuffer = Buffer.alloc(0)\n\n this.log(`detach: handler cleaned up`)\n return this\n }\n\n public get isAttached(): boolean {\n return this.socket !== null\n }\n\n private async handleData(data: Buffer): Promise<number> {\n if (!this.socket || !this.active) {\n this.log(`handleData: no active socket, ignoring data`)\n return 0\n }\n\n this.log(`handleData: received ${data.length} bytes`)\n\n // Append to buffer for message reassembly\n this.messageBuffer = Buffer.concat([this.messageBuffer, data])\n\n // Print the incoming data to the console\n this.inspectData('incoming', data)\n\n try {\n let totalProcessed = 0\n\n while (this.messageBuffer.length > 0) {\n // Determine message length\n let messageLength = 0\n let isComplete = false\n\n // Handle startup message (no type byte, just length)\n if (this.messageBuffer.length >= 4) {\n const firstInt = this.messageBuffer.readInt32BE(0)\n\n if (this.messageBuffer.length >= 8) {\n const secondInt = this.messageBuffer.readInt32BE(4)\n // PostgreSQL 3.0 protocol version\n if (secondInt === 196608 || secondInt === 0x00030000) {\n messageLength = firstInt\n isComplete = this.messageBuffer.length >= messageLength\n }\n }\n\n // Regular message (type byte + length)\n if (!isComplete && this.messageBuffer.length >= 5) {\n const msgLength = this.messageBuffer.readInt32BE(1)\n messageLength = 1 + msgLength\n isComplete = this.messageBuffer.length >= messageLength\n }\n }\n\n if (!isComplete || messageLength === 0) {\n this.log(\n `handleData: incomplete message, buffering ${this.messageBuffer.length} bytes`,\n )\n break\n }\n\n // Extract and process complete message\n const message = this.messageBuffer.slice(0, messageLength)\n this.messageBuffer = this.messageBuffer.slice(messageLength)\n\n this.log(`handleData: processing message of ${message.length} bytes`)\n\n // Check if socket is still active before processing\n if (!this.active || !this.socket) {\n this.log(`handleData: socket no longer active, stopping processing`)\n break\n }\n\n // Queue the query for execution\n // This allows multiple connections to queue queries simultaneously\n const result = await this.queryQueue.enqueue(\n this.id,\n new Uint8Array(message),\n )\n\n this.log(`handleData: received ${result.length} bytes from PGlite`)\n\n // Print the outgoing data to the console\n this.inspectData('outgoing', result)\n\n // Send response if available\n if (\n result.length > 0 &&\n this.socket &&\n this.socket.writable &&\n this.active\n ) {\n await new Promise<number>((resolve, reject) => {\n this.log(`handleData: writing response to socket`)\n if (this.socket?.writable) {\n this.socket.write(Buffer.from(result), (err?: any) => {\n if (err) {\n this.log(`handleData: error writing to socket:`, err)\n reject(err)\n } else {\n this.log(`handleData: socket sent: ${result.length} bytes`)\n resolve(result.length)\n }\n })\n } else {\n this.log(`handleData: socket no longer writable`)\n resolve(0)\n }\n }).catch((writeErr) => {\n this.log(`handleData: failed to write to socket:`, writeErr)\n throw writeErr\n })\n }\n\n totalProcessed += result.length\n }\n\n // Emit data event with byte sizes\n this.dispatchEvent(\n new CustomEvent('data', {\n detail: { incoming: data.length, outgoing: totalProcessed },\n }),\n )\n\n return totalProcessed\n } catch (err) {\n this.log(`handleData: error processing data:`, err)\n throw err\n }\n }\n\n private handleError(err: Error): void {\n if (!this.active) {\n this.log(`handleError: handler not active, ignoring error`)\n return\n }\n\n // ECONNRESET is expected behavior when clients disconnect\n if (err.message?.includes('ECONNRESET')) {\n this.log(\n `handleError: client disconnected (ECONNRESET) - normal behavior`,\n )\n } else if (err.message?.includes('Idle timeout')) {\n this.log(`handleError: connection idle timeout`)\n } else {\n this.log(`handleError:`, err)\n }\n\n this.active = false\n\n // Emit error event\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n\n // Clean up\n this.detach(true)\n }\n\n private handleClose(): void {\n this.log(`handleClose: socket closed`)\n this.active = false\n this.dispatchEvent(new CustomEvent('close'))\n this.detach(false)\n }\n\n private inspectData(\n direction: 'incoming' | 'outgoing',\n data: Buffer | Uint8Array,\n ): void {\n if (!this.inspect) return\n console.log('-'.repeat(75))\n if (direction === 'incoming') {\n console.log('-> incoming', data.length, 'bytes')\n } else {\n console.log('<- outgoing', data.length, 'bytes')\n }\n\n for (let offset = 0; offset < data.length; offset += 16) {\n const chunkSize = Math.min(16, data.length - offset)\n\n let hexPart = ''\n for (let i = 0; i < 16; i++) {\n if (i < chunkSize) {\n const byte = data[offset + i]\n hexPart += byte.toString(16).padStart(2, '0') + ' '\n } else {\n hexPart += ' '\n }\n }\n\n let asciiPart = ''\n for (let i = 0; i < chunkSize; i++) {\n const byte = data[offset + i]\n asciiPart += byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : '.'\n }\n\n console.log(\n `${offset.toString(16).padStart(8, '0')} ${hexPart} ${asciiPart}`,\n )\n }\n }\n}\n\n/**\n * Options for creating a PGLiteSocketServer\n */\nexport interface PGLiteSocketServerOptions {\n /** The PGlite database instance */\n db: PGlite\n /** The port to listen on (default: 5432) */\n port?: number\n /** The host to bind to (default: 127.0.0.1) */\n host?: string\n /** Unix socket path to bind to (default: undefined) */\n path?: string\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n /** Idle timeout in ms (0 to disable, default: 0) */\n idleTimeout?: number\n /** Maximum concurrent connections (default: 100) */\n maxConnections?: number\n}\n\n/**\n * PGLite Socket Server with support for multiple concurrent connections\n * Connections remain open and queries are queued at the query level\n */\nexport class PGLiteSocketServer extends EventTarget {\n readonly db: PGlite\n private server: Server | null = null\n private port?: number\n private host?: string\n private path?: string\n private active = false\n private inspect: boolean\n private debug: boolean\n private idleTimeout: number\n private maxConnections: number\n private handlers: Set<PGLiteSocketHandler> = new Set()\n private queryQueue: QueryQueueManager\n\n constructor(options: PGLiteSocketServerOptions) {\n super()\n this.db = options.db\n if (options.path) {\n this.path = options.path\n } else {\n if (typeof options.port === 'number') {\n // Keep port undefined on port 0, will be set by the OS when we start the server.\n this.port = options.port ?? options.port\n } else {\n this.port = 5432\n }\n this.host = options.host || '127.0.0.1'\n }\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.idleTimeout = options.idleTimeout ?? 0\n this.maxConnections = options.maxConnections ?? 1\n\n // Create the shared query queue\n this.queryQueue = new QueryQueueManager(this.db, this.debug)\n\n this.log(`constructor: created server on ${this.getServerConn()}`)\n this.log(`constructor: max connections: ${this.maxConnections}`)\n if (this.idleTimeout > 0) {\n this.log(`constructor: idle timeout: ${this.idleTimeout}ms`)\n }\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketServer] ${message}`, ...args)\n }\n }\n\n public async start(): Promise<void> {\n this.log(`start: starting server on ${this.getServerConn()}`)\n\n if (this.server) {\n throw new Error('Socket server already started')\n }\n\n // Ensure PGlite is ready before accepting connections\n await this.db.waitReady\n\n this.active = true\n this.server = createServer((socket) => {\n setImmediate(() => this.handleConnection(socket))\n })\n\n this.server.maxConnections = this.maxConnections\n\n return new Promise<void>((resolve, reject) => {\n if (!this.server) return reject(new Error('Server not initialized'))\n\n this.server.on('error', (err) => {\n this.log(`start: server error:`, err)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n if (!this.active) {\n reject(err)\n }\n })\n\n if (this.path) {\n this.server.listen(this.path, () => {\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { path: this.path },\n }),\n )\n resolve()\n })\n } else {\n const server = this.server\n server.listen(this.port, this.host, () => {\n const address = server.address()\n // We are not using pipes, so return type should be AddressInfo\n if (address === null || typeof address !== 'object') {\n throw Error('Expected address info')\n }\n // Assign the new port number\n this.port = address.port\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { port: this.port, host: this.host },\n }),\n )\n resolve()\n })\n }\n })\n }\n\n public getServerConn(): string {\n if (this.path) return this.path\n return `${this.host}:${this.port}`\n }\n\n public async stop(): Promise<void> {\n this.log(`stop: stopping server`)\n\n this.active = false\n\n // Detach all handlers\n this.log(`stop: detaching ${this.handlers.size} handlers`)\n for (const handler of this.handlers) {\n handler.detach(true)\n }\n this.handlers.clear()\n\n if (!this.server) {\n this.log(`stop: server not running, nothing to do`)\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve) => {\n if (!this.server) return resolve()\n\n this.server.close(() => {\n this.log(`stop: server closed`)\n this.server = null\n this.dispatchEvent(new CustomEvent('close'))\n resolve()\n })\n })\n }\n\n private async handleConnection(socket: Socket): Promise<void> {\n const clientInfo = {\n clientAddress: socket.remoteAddress || 'unknown',\n clientPort: socket.remotePort || 0,\n }\n\n this.log(\n `handleConnection: new connection from ${clientInfo.clientAddress}:${clientInfo.clientPort}`,\n )\n this.log(\n `handleConnection: active connections: ${this.handlers.size}, queued queries: ${this.queryQueue.getQueueLength()}`,\n )\n\n if (!this.active) {\n this.log(`handleConnection: server not active, closing connection`)\n try {\n socket.end()\n } catch (err) {\n this.log(`handleConnection: error closing socket:`, err)\n }\n return\n }\n\n // Check connection limit\n if (this.handlers.size >= this.maxConnections) {\n this.log(`handleConnection: max connections reached, rejecting`)\n socket.write(Buffer.from('Too many connections\\n'))\n socket.end()\n return\n }\n\n // Create a new handler for this connection\n const handler = new PGLiteSocketHandler({\n queryQueue: this.queryQueue,\n closeOnDetach: true,\n inspect: this.inspect,\n debug: this.debug,\n idleTimeout: this.idleTimeout,\n })\n\n // Track this handler\n this.handlers.add(handler)\n\n // Handle errors\n handler.addEventListener('error', (event) => {\n const error = (event as CustomEvent<Error>).detail\n\n if (error?.message?.includes('ECONNRESET')) {\n this.log(\n `handler #${handler.handlerId}: client disconnected (ECONNRESET)`,\n )\n } else if (error?.message?.includes('Idle timeout')) {\n this.log(`handler #${handler.handlerId}: idle timeout`)\n } else {\n this.log(`handler #${handler.handlerId}: error:`, error)\n }\n })\n\n // Handle close event\n handler.addEventListener('close', () => {\n this.log(`handler #${handler.handlerId}: closed`)\n this.handlers.delete(handler)\n this.log(`handleConnection: active connections: ${this.handlers.size}`)\n })\n\n try {\n await handler.attach(socket)\n this.dispatchEvent(new CustomEvent('connection', { detail: clientInfo }))\n } catch (err) {\n this.log(`handleConnection: error attaching socket:`, err)\n this.handlers.delete(handler)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n try {\n socket.end()\n } catch (closeErr) {\n this.log(`handleConnection: error closing socket:`, closeErr)\n }\n }\n }\n\n public getStats() {\n return {\n activeConnections: this.handlers.size,\n queuedQueries: this.queryQueue.getQueueLength(),\n maxConnections: this.maxConnections,\n }\n }\n}\n"],"mappings":"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","names":["src_exports","__export","CONNECTION_QUEUE_TIMEOUT","PGLiteSocketHandler","PGLiteSocketServer","__toCommonJS","import_net","CONNECTION_QUEUE_TIMEOUT","QueryQueueManager","db","debug","message","args","handlerId","resolve","reject","query","q","waitTime","result","error","before","removed","_PGLiteSocketHandler","options","socket","data","err","idleTime","close","totalProcessed","messageLength","isComplete","firstInt","secondInt","writeErr","direction","offset","chunkSize","hexPart","i","byte","asciiPart","PGLiteSocketHandler","PGLiteSocketServer","server","address","handler","clientInfo","event","closeErr"]}
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { PGlite } from '@electric-sql/pglite'\nimport { type Server, type Socket, createServer } from 'net'\n\n// Connection queue timeout in milliseconds\nexport const CONNECTION_QUEUE_TIMEOUT = 60000 // 60 seconds\n\n/**\n * Represents a queued query waiting for PGlite access\n */\ninterface QueuedQuery {\n handlerId: number\n message: Uint8Array\n resolve: (resultSize: number) => void\n reject: (error: Error) => void\n timestamp: number\n onData: (data: Uint8Array) => void\n}\n\n/**\n * Global query queue manager\n * Ensures only one query executes at a time in PGlite\n */\nclass QueryQueueManager {\n private queue: QueuedQuery[] = []\n private processing = false\n private db: PGlite\n private debug: boolean\n private lastHandlerId: null | number = null\n\n constructor(db: PGlite, debug = false) {\n this.db = db\n this.debug = debug\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[QueryQueueManager] ${message}`, ...args)\n }\n }\n\n async enqueue(\n handlerId: number,\n message: Uint8Array,\n onData: (data: Uint8Array) => void,\n ): Promise<number> {\n return new Promise((resolve, reject) => {\n const query: QueuedQuery = {\n handlerId,\n message,\n resolve,\n reject,\n timestamp: Date.now(),\n onData,\n }\n\n this.queue.push(query)\n this.log(\n `enqueued query from handler #${handlerId}, queue size: ${this.queue.length}`,\n )\n\n // Process queue if not already processing\n if (!this.processing) {\n this.processQueue()\n }\n })\n }\n\n private async processQueue(): Promise<void> {\n if (this.processing || this.queue.length === 0) {\n return\n }\n\n this.processing = true\n\n while (this.queue.length > 0) {\n let query\n\n if (this.db.isInTransaction() && this.lastHandlerId) {\n const i = this.queue.findIndex(\n (q) => q.handlerId === this.lastHandlerId,\n )\n if (i === -1) {\n // we didn't find any other query from the same client!\n this.log(\n `transaction started, but no query from the same handler id found in queue`,\n this.lastHandlerId,\n )\n query = null\n } else {\n query = this.queue.splice(i, 1)[0]\n }\n } else {\n query = this.queue.shift()\n }\n if (!query) break\n\n const waitTime = Date.now() - query.timestamp\n this.log(\n `processing query from handler #${query.handlerId} (waited ${waitTime}ms)`,\n )\n\n let result = 0\n try {\n // Execute the query with exclusive access to PGlite\n await this.db.runExclusive(async () => {\n return await this.db.execProtocolRawStream(query.message, {\n onRawData: (data) => {\n result += data.length\n query.onData(data)\n },\n })\n })\n } catch (error) {\n this.log(`query from handler #${query.handlerId} failed:`, error)\n query.reject(error as Error)\n return\n }\n\n this.log(\n `query from handler #${query.handlerId} completed, ${result} bytes`,\n )\n this.lastHandlerId = query.handlerId\n query.resolve(result)\n }\n\n this.processing = false\n this.log(`queue processing complete, queue length is`, this.queue.length)\n }\n\n getQueueLength(): number {\n return this.queue.length\n }\n\n clearQueueForHandler(handlerId: number): void {\n const before = this.queue.length\n this.queue = this.queue.filter((q) => {\n if (q.handlerId === handlerId) {\n q.reject(new Error('Handler disconnected'))\n return false\n }\n return true\n })\n const removed = before - this.queue.length\n if (removed > 0) {\n this.log(`cleared ${removed} queries for handler #${handlerId}`)\n }\n }\n\n async clearTransactionIfNeeded(handlerId: number): Promise<void> {\n if (this.db.isInTransaction() && this.lastHandlerId === handlerId) {\n await this.db.exec('ROLLBACK')\n this.lastHandlerId = null\n await this.processQueue()\n }\n }\n}\n\n/**\n * Options for creating a PGLiteSocketHandler\n */\nexport interface PGLiteSocketHandlerOptions {\n /** The query queue manager */\n queryQueue: QueryQueueManager\n /** Whether to close the socket when detached (default: false) */\n closeOnDetach?: boolean\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n /** Idle timeout in ms (0 to disable, default: 0) */\n idleTimeout?: number\n}\n\n/**\n * Handler for a single socket connection to PGlite\n * Each connection can remain open and send multiple queries\n */\nexport class PGLiteSocketHandler extends EventTarget {\n private queryQueue: QueryQueueManager\n private socket: Socket | null = null\n private active = false\n private closeOnDetach: boolean\n private inspect: boolean\n private debug: boolean\n private readonly id: number\n private messageBuffer: Buffer = Buffer.alloc(0)\n private idleTimer?: NodeJS.Timeout\n private idleTimeout: number\n private lastActivityTime: number = Date.now()\n\n // Static counter for generating unique handler IDs\n private static nextHandlerId = 1\n\n constructor(options: PGLiteSocketHandlerOptions) {\n super()\n this.queryQueue = options.queryQueue\n this.closeOnDetach = options.closeOnDetach ?? false\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.idleTimeout = options.idleTimeout ?? 0\n this.id = PGLiteSocketHandler.nextHandlerId++\n\n this.log('constructor: created new handler')\n }\n\n public get handlerId(): number {\n return this.id\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketHandler#${this.id}] ${message}`, ...args)\n }\n }\n\n public async attach(socket: Socket): Promise<PGLiteSocketHandler> {\n this.log(\n `attach: attaching socket from ${socket.remoteAddress}:${socket.remotePort}`,\n )\n\n if (this.socket) {\n throw new Error('Socket already attached')\n }\n\n this.socket = socket\n this.active = true\n this.lastActivityTime = Date.now()\n\n // Set up socket options\n socket.setNoDelay(true)\n\n // Set up idle timeout if configured\n if (this.idleTimeout > 0) {\n this.resetIdleTimer()\n }\n\n // Setup event handlers\n this.log(`attach: setting up socket event handlers`)\n\n socket.on('data', (data) => {\n this.lastActivityTime = Date.now()\n this.resetIdleTimer()\n\n setImmediate(async () => {\n try {\n await this.handleData(data)\n } catch (err) {\n this.log('socket on data error: ', err)\n this.handleError(err as Error)\n }\n })\n })\n\n socket.on('error', (err) => {\n setImmediate(() => this.handleError(err))\n })\n\n socket.on('close', () => {\n setImmediate(() => this.handleClose())\n })\n\n this.log(`attach: socket handler ready`)\n return this\n }\n\n private resetIdleTimer(): void {\n if (this.idleTimeout <= 0) return\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n }\n\n this.idleTimer = setTimeout(() => {\n const idleTime = Date.now() - this.lastActivityTime\n this.log(`idle timeout after ${idleTime}ms`)\n this.handleError(new Error('Idle timeout'))\n }, this.idleTimeout)\n }\n\n public async detach(close?: boolean): Promise<PGLiteSocketHandler> {\n this.log(`detach: detaching socket, close=${close ?? this.closeOnDetach}`)\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n this.idleTimer = undefined\n }\n\n // Clear any pending queries for this handler\n this.queryQueue.clearQueueForHandler(this.id)\n\n await this.queryQueue.clearTransactionIfNeeded(this.id)\n\n if (!this.socket) {\n this.log(`detach: no socket attached, nothing to do`)\n return this\n }\n\n // Remove all listeners\n this.socket.removeAllListeners('data')\n this.socket.removeAllListeners('error')\n this.socket.removeAllListeners('close')\n\n // Close the socket if requested\n if (close ?? this.closeOnDetach) {\n if (this.socket.writable) {\n this.log(`detach: closing socket`)\n try {\n this.socket.end()\n this.socket.destroy()\n } catch (err) {\n this.log(`detach: error closing socket:`, err)\n }\n }\n }\n\n this.socket = null\n this.active = false\n this.messageBuffer = Buffer.alloc(0)\n\n this.log(`detach: handler cleaned up`)\n return this\n }\n\n public get isAttached(): boolean {\n return this.socket !== null\n }\n\n private async handleData(data: Buffer): Promise<number> {\n if (!this.socket || !this.active) {\n this.log(`handleData: no active socket, ignoring data`)\n return 0\n }\n\n this.log(`handleData: received ${data.length} bytes`)\n\n // Append to buffer for message reassembly\n this.messageBuffer = Buffer.concat([this.messageBuffer, data])\n\n // Print the incoming data to the console\n this.inspectData('incoming', data)\n\n try {\n let totalProcessed = 0\n\n while (this.messageBuffer.length > 0) {\n // Determine message length\n let messageLength = 0\n let isComplete = false\n\n // Handle startup message (no type byte, just length)\n if (this.messageBuffer.length >= 4) {\n const firstInt = this.messageBuffer.readInt32BE(0)\n\n if (this.messageBuffer.length >= 8) {\n const secondInt = this.messageBuffer.readInt32BE(4)\n // PostgreSQL 3.0 protocol version\n if (secondInt === 196608 || secondInt === 0x00030000) {\n messageLength = firstInt\n isComplete = this.messageBuffer.length >= messageLength\n }\n }\n\n // Regular message (type byte + length)\n if (!isComplete && this.messageBuffer.length >= 5) {\n const msgLength = this.messageBuffer.readInt32BE(1)\n messageLength = 1 + msgLength\n isComplete = this.messageBuffer.length >= messageLength\n }\n }\n\n if (!isComplete || messageLength === 0) {\n this.log(\n `handleData: incomplete message, buffering ${this.messageBuffer.length} bytes`,\n )\n break\n }\n\n // Extract and process complete message\n const message = this.messageBuffer.slice(0, messageLength)\n this.messageBuffer = this.messageBuffer.slice(messageLength)\n\n this.log(`handleData: processing message of ${message.length} bytes`)\n\n // Check if socket is still active before processing\n if (!this.active || !this.socket) {\n this.log(`handleData: socket no longer active, stopping processing`)\n break\n }\n\n let socketWriteError: any = undefined\n // Queue the query for execution\n // This allows multiple connections to queue queries simultaneously\n await this.queryQueue.enqueue(\n this.id,\n new Uint8Array(message),\n (data) => {\n this.log(`handleData: received ${data.length} bytes from PGlite`)\n\n // Print the outgoing data to the console\n this.inspectData('outgoing', data)\n\n // Send response if available\n if (\n data.length > 0 &&\n this.socket &&\n this.socket.writable &&\n this.active\n ) {\n // await new Promise<number>((resolve, reject) => {\n this.log(`handleData: writing response to socket`)\n if (this.socket?.writable) {\n this.socket.write(Buffer.from(data), (err?: any) => {\n if (err) {\n this.log(`handleData: error writing to socket:`, err)\n socketWriteError = err\n } else {\n this.log(`handleData: socket sent: ${data.length} bytes`)\n }\n })\n } else {\n this.log(`handleData: socket no longer writable`)\n }\n }\n totalProcessed += data.length\n },\n )\n if (socketWriteError) throw socketWriteError\n }\n\n // Emit data event with byte sizes\n this.dispatchEvent(\n new CustomEvent('data', {\n detail: { incoming: data.length, outgoing: totalProcessed },\n }),\n )\n\n return totalProcessed\n } catch (err) {\n this.log(`handleData: error processing data:`, err)\n throw err\n }\n }\n\n private handleError(err: Error): void {\n if (!this.active) {\n this.log(`handleError: handler not active, ignoring error`)\n return\n }\n\n // ECONNRESET is expected behavior when clients disconnect\n if (err.message?.includes('ECONNRESET')) {\n this.log(\n `handleError: client disconnected (ECONNRESET) - normal behavior`,\n )\n } else if (err.message?.includes('Idle timeout')) {\n this.log(`handleError: connection idle timeout`)\n } else {\n this.log(`handleError:`, err)\n }\n\n this.active = false\n\n // Emit error event\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n\n // Clean up\n this.detach(true)\n }\n\n private handleClose(): void {\n this.log(`handleClose: socket closed`)\n this.active = false\n this.dispatchEvent(new CustomEvent('close'))\n this.detach(false)\n }\n\n private inspectData(\n direction: 'incoming' | 'outgoing',\n data: Buffer | Uint8Array,\n ): void {\n if (!this.inspect) return\n console.log('-'.repeat(75))\n if (direction === 'incoming') {\n console.log('-> incoming', data.length, 'bytes')\n } else {\n console.log('<- outgoing', data.length, 'bytes')\n }\n\n for (let offset = 0; offset < data.length; offset += 16) {\n const chunkSize = Math.min(16, data.length - offset)\n\n let hexPart = ''\n for (let i = 0; i < 16; i++) {\n if (i < chunkSize) {\n const byte = data[offset + i]\n hexPart += byte.toString(16).padStart(2, '0') + ' '\n } else {\n hexPart += ' '\n }\n }\n\n let asciiPart = ''\n for (let i = 0; i < chunkSize; i++) {\n const byte = data[offset + i]\n asciiPart += byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : '.'\n }\n\n console.log(\n `${offset.toString(16).padStart(8, '0')} ${hexPart} ${asciiPart}`,\n )\n }\n }\n}\n\n/**\n * Options for creating a PGLiteSocketServer\n */\nexport interface PGLiteSocketServerOptions {\n /** The PGlite database instance */\n db: PGlite\n /** The port to listen on (default: 5432) */\n port?: number\n /** The host to bind to (default: 127.0.0.1) */\n host?: string\n /** Unix socket path to bind to (default: undefined) */\n path?: string\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n /** Idle timeout in ms (0 to disable, default: 0) */\n idleTimeout?: number\n /** Maximum concurrent connections (default: 100) */\n maxConnections?: number\n}\n\n/**\n * PGLite Socket Server with support for multiple concurrent connections\n * Connections remain open and queries are queued at the query level\n */\nexport class PGLiteSocketServer extends EventTarget {\n readonly db: PGlite\n private server: Server | null = null\n private port?: number\n private host?: string\n private path?: string\n private active = false\n private inspect: boolean\n private debug: boolean\n private idleTimeout: number\n private maxConnections: number\n private handlers: Set<PGLiteSocketHandler> = new Set()\n private queryQueue: QueryQueueManager\n\n constructor(options: PGLiteSocketServerOptions) {\n super()\n this.db = options.db\n if (options.path) {\n this.path = options.path\n } else {\n if (typeof options.port === 'number') {\n // Keep port undefined on port 0, will be set by the OS when we start the server.\n this.port = options.port ?? options.port\n } else {\n this.port = 5432\n }\n this.host = options.host || '127.0.0.1'\n }\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.idleTimeout = options.idleTimeout ?? 0\n this.maxConnections = options.maxConnections ?? 1\n\n // Create the shared query queue\n this.queryQueue = new QueryQueueManager(this.db, this.debug)\n\n this.log(`constructor: created server on ${this.getServerConn()}`)\n this.log(`constructor: max connections: ${this.maxConnections}`)\n if (this.idleTimeout > 0) {\n this.log(`constructor: idle timeout: ${this.idleTimeout}ms`)\n }\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketServer] ${message}`, ...args)\n }\n }\n\n public async start(): Promise<void> {\n this.log(`start: starting server on ${this.getServerConn()}`)\n\n if (this.server) {\n throw new Error('Socket server already started')\n }\n\n // Ensure PGlite is ready before accepting connections\n await this.db.waitReady\n\n this.active = true\n this.server = createServer((socket) => {\n setImmediate(() => this.handleConnection(socket))\n })\n\n this.server.maxConnections = this.maxConnections\n\n return new Promise<void>((resolve, reject) => {\n if (!this.server) return reject(new Error('Server not initialized'))\n\n this.server.on('error', (err) => {\n this.log(`start: server error:`, err)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n if (!this.active) {\n reject(err)\n }\n })\n\n if (this.path) {\n this.server.listen(this.path, () => {\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { path: this.path },\n }),\n )\n resolve()\n })\n } else {\n const server = this.server\n server.listen(this.port, this.host, () => {\n const address = server.address()\n // We are not using pipes, so return type should be AddressInfo\n if (address === null || typeof address !== 'object') {\n throw Error('Expected address info')\n }\n // Assign the new port number\n this.port = address.port\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { port: this.port, host: this.host },\n }),\n )\n resolve()\n })\n }\n })\n }\n\n public getServerConn(): string {\n if (this.path) return this.path\n return `${this.host}:${this.port}`\n }\n\n public async stop(): Promise<void> {\n this.log(`stop: stopping server`)\n\n this.active = false\n\n // Detach all handlers\n this.log(`stop: detaching ${this.handlers.size} handlers`)\n for (const handler of this.handlers) {\n handler.detach(true)\n }\n this.handlers.clear()\n\n if (!this.server) {\n this.log(`stop: server not running, nothing to do`)\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve) => {\n if (!this.server) return resolve()\n\n this.server.close(() => {\n this.log(`stop: server closed`)\n this.server = null\n this.dispatchEvent(new CustomEvent('close'))\n resolve()\n })\n })\n }\n\n private async handleConnection(socket: Socket): Promise<void> {\n const clientInfo = {\n clientAddress: socket.remoteAddress || 'unknown',\n clientPort: socket.remotePort || 0,\n }\n\n this.log(\n `handleConnection: new connection from ${clientInfo.clientAddress}:${clientInfo.clientPort}`,\n )\n this.log(\n `handleConnection: active connections: ${this.handlers.size}, queued queries: ${this.queryQueue.getQueueLength()}`,\n )\n\n if (!this.active) {\n this.log(`handleConnection: server not active, closing connection`)\n try {\n socket.end()\n } catch (err) {\n this.log(`handleConnection: error closing socket:`, err)\n }\n return\n }\n\n // Check connection limit\n if (this.handlers.size >= this.maxConnections) {\n this.log(`handleConnection: max connections reached, rejecting`)\n socket.write(Buffer.from('Too many connections\\n'))\n socket.end()\n return\n }\n\n // Create a new handler for this connection\n const handler = new PGLiteSocketHandler({\n queryQueue: this.queryQueue,\n closeOnDetach: true,\n inspect: this.inspect,\n debug: this.debug,\n idleTimeout: this.idleTimeout,\n })\n\n // Track this handler\n this.handlers.add(handler)\n\n // Handle errors\n handler.addEventListener('error', (event) => {\n const error = (event as CustomEvent<Error>).detail\n\n if (error?.message?.includes('ECONNRESET')) {\n this.log(\n `handler #${handler.handlerId}: client disconnected (ECONNRESET)`,\n )\n } else if (error?.message?.includes('Idle timeout')) {\n this.log(`handler #${handler.handlerId}: idle timeout`)\n } else {\n this.log(`handler #${handler.handlerId}: error:`, error)\n }\n })\n\n // Handle close event\n handler.addEventListener('close', () => {\n this.log(`handler #${handler.handlerId}: closed`)\n this.handlers.delete(handler)\n this.log(`handleConnection: active connections: ${this.handlers.size}`)\n })\n\n try {\n await handler.attach(socket)\n this.dispatchEvent(new CustomEvent('connection', { detail: clientInfo }))\n } catch (err) {\n this.log(`handleConnection: error attaching socket:`, err)\n this.handlers.delete(handler)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n try {\n socket.end()\n } catch (closeErr) {\n this.log(`handleConnection: error closing socket:`, closeErr)\n }\n }\n }\n\n public getStats() {\n return {\n activeConnections: this.handlers.size,\n queuedQueries: this.queryQueue.getQueueLength(),\n maxConnections: this.maxConnections,\n }\n }\n}\n"],"mappings":"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","names":["src_exports","__export","CONNECTION_QUEUE_TIMEOUT","PGLiteSocketHandler","PGLiteSocketServer","__toCommonJS","import_net","CONNECTION_QUEUE_TIMEOUT","QueryQueueManager","db","debug","message","args","handlerId","onData","resolve","reject","query","i","q","waitTime","result","data","error","before","removed","_PGLiteSocketHandler","options","socket","err","idleTime","close","totalProcessed","messageLength","isComplete","firstInt","secondInt","socketWriteError","direction","offset","chunkSize","hexPart","byte","asciiPart","PGLiteSocketHandler","PGLiteSocketServer","server","address","handler","clientInfo","event","closeErr"]}

@@ -17,3 +17,3 @@ import { PGlite } from '@electric-sql/pglite';

private log;
enqueue(handlerId: number, message: Uint8Array): Promise<Uint8Array>;
enqueue(handlerId: number, message: Uint8Array, onData: (data: Uint8Array) => void): Promise<number>;
private processQueue;

@@ -20,0 +20,0 @@ getQueueLength(): number;

@@ -17,3 +17,3 @@ import { PGlite } from '@electric-sql/pglite';

private log;
enqueue(handlerId: number, message: Uint8Array): Promise<Uint8Array>;
enqueue(handlerId: number, message: Uint8Array, onData: (data: Uint8Array) => void): Promise<number>;
private processQueue;

@@ -20,0 +20,0 @@ getQueueLength(): number;

@@ -1,2 +0,2 @@

import{a,b,c}from"./chunk-JGAU6COP.js";export{a as CONNECTION_QUEUE_TIMEOUT,b as PGLiteSocketHandler,c as PGLiteSocketServer};
import{a,b,c}from"./chunk-NSUMFCRM.js";export{a as CONNECTION_QUEUE_TIMEOUT,b as PGLiteSocketHandler,c as PGLiteSocketServer};
//# sourceMappingURL=index.js.map
#!/usr/bin/env node
"use strict";var y=require("@electric-sql/pglite");var b=require("net");var p=class{constructor(s,e=!1){this.queue=[];this.processing=!1;this.lastHandlerId=null;this.db=s,this.debug=e}log(s,...e){this.debug&&console.log(`[QueryQueueManager] ${s}`,...e)}async enqueue(s,e){return new Promise((t,i)=>{let r={handlerId:s,message:e,resolve:t,reject:i,timestamp:Date.now()};this.queue.push(r),this.log(`enqueued query from handler #${s}, queue size: ${this.queue.length}`),this.processing||this.processQueue()})}async processQueue(){if(!(this.processing||this.queue.length===0)){for(this.processing=!0;this.queue.length>0;){let s;if(this.db.isInTransaction()&&this.lastHandlerId){let t=this.queue.findIndex(i=>i.handlerId===this.lastHandlerId);t===-1?(this.log("transaction started, but no query from the same handler id found in queue",this.lastHandlerId),s=null):s=this.queue.splice(t,1)[0]}else s=this.queue.shift();if(!s)break;let e=Date.now()-s.timestamp;this.log(`processing query from handler #${s.handlerId} (waited ${e}ms)`);try{let t=await this.db.runExclusive(async()=>await this.db.execProtocolRaw(s.message));this.log(`query from handler #${s.handlerId} completed, ${t.length} bytes`),this.lastHandlerId=s.handlerId,s.resolve(t)}catch(t){this.log(`query from handler #${s.handlerId} failed:`,t),s.reject(t)}}this.processing=!1,this.log("queue processing complete, queue length is",this.queue.length)}}getQueueLength(){return this.queue.length}clearQueueForHandler(s){let e=this.queue.length;this.queue=this.queue.filter(i=>i.handlerId===s?(i.reject(new Error("Handler disconnected")),!1):!0);let t=e-this.queue.length;t>0&&this.log(`cleared ${t} queries for handler #${s}`)}async clearTransactionIfNeeded(s){this.db.isInTransaction()&&this.lastHandlerId===s&&(await this.db.exec("ROLLBACK"),this.lastHandlerId=null,await this.processQueue())}},u=class u extends EventTarget{constructor(e){super();this.socket=null;this.active=!1;this.messageBuffer=Buffer.alloc(0);this.lastActivityTime=Date.now();this.queryQueue=e.queryQueue,this.closeOnDetach=e.closeOnDetach??!1,this.inspect=e.inspect??!1,this.debug=e.debug??!1,this.idleTimeout=e.idleTimeout??0,this.id=u.nextHandlerId++,this.log("constructor: created new handler")}get handlerId(){return this.id}log(e,...t){this.debug&&console.log(`[PGLiteSocketHandler#${this.id}] ${e}`,...t)}async attach(e){if(this.log(`attach: attaching socket from ${e.remoteAddress}:${e.remotePort}`),this.socket)throw new Error("Socket already attached");return this.socket=e,this.active=!0,this.lastActivityTime=Date.now(),e.setNoDelay(!0),this.idleTimeout>0&&this.resetIdleTimer(),this.log("attach: setting up socket event handlers"),e.on("data",t=>{this.lastActivityTime=Date.now(),this.resetIdleTimer(),setImmediate(async()=>{try{await this.handleData(t)}catch(i){this.log("socket on data error: ",i),this.handleError(i)}})}),e.on("error",t=>{setImmediate(()=>this.handleError(t))}),e.on("close",()=>{setImmediate(()=>this.handleClose())}),this.log("attach: socket handler ready"),this}resetIdleTimer(){this.idleTimeout<=0||(this.idleTimer&&clearTimeout(this.idleTimer),this.idleTimer=setTimeout(()=>{let e=Date.now()-this.lastActivityTime;this.log(`idle timeout after ${e}ms`),this.handleError(new Error("Idle timeout"))},this.idleTimeout))}async detach(e){if(this.log(`detach: detaching socket, close=${e??this.closeOnDetach}`),this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=void 0),this.queryQueue.clearQueueForHandler(this.id),await this.queryQueue.clearTransactionIfNeeded(this.id),!this.socket)return this.log("detach: no socket attached, nothing to do"),this;if(this.socket.removeAllListeners("data"),this.socket.removeAllListeners("error"),this.socket.removeAllListeners("close"),(e??this.closeOnDetach)&&this.socket.writable){this.log("detach: closing socket");try{this.socket.end(),this.socket.destroy()}catch(t){this.log("detach: error closing socket:",t)}}return this.socket=null,this.active=!1,this.messageBuffer=Buffer.alloc(0),this.log("detach: handler cleaned up"),this}get isAttached(){return this.socket!==null}async handleData(e){if(!this.socket||!this.active)return this.log("handleData: no active socket, ignoring data"),0;this.log(`handleData: received ${e.length} bytes`),this.messageBuffer=Buffer.concat([this.messageBuffer,e]),this.inspectData("incoming",e);try{let t=0;for(;this.messageBuffer.length>0;){let i=0,r=!1;if(this.messageBuffer.length>=4){let o=this.messageBuffer.readInt32BE(0);if(this.messageBuffer.length>=8){let l=this.messageBuffer.readInt32BE(4);(l===196608||l===196608)&&(i=o,r=this.messageBuffer.length>=i)}!r&&this.messageBuffer.length>=5&&(i=1+this.messageBuffer.readInt32BE(1),r=this.messageBuffer.length>=i)}if(!r||i===0){this.log(`handleData: incomplete message, buffering ${this.messageBuffer.length} bytes`);break}let n=this.messageBuffer.slice(0,i);if(this.messageBuffer=this.messageBuffer.slice(i),this.log(`handleData: processing message of ${n.length} bytes`),!this.active||!this.socket){this.log("handleData: socket no longer active, stopping processing");break}let a=await this.queryQueue.enqueue(this.id,new Uint8Array(n));this.log(`handleData: received ${a.length} bytes from PGlite`),this.inspectData("outgoing",a),a.length>0&&this.socket&&this.socket.writable&&this.active&&await new Promise((o,l)=>{this.log("handleData: writing response to socket"),this.socket?.writable?this.socket.write(Buffer.from(a),m=>{m?(this.log("handleData: error writing to socket:",m),l(m)):(this.log(`handleData: socket sent: ${a.length} bytes`),o(a.length))}):(this.log("handleData: socket no longer writable"),o(0))}).catch(o=>{throw this.log("handleData: failed to write to socket:",o),o}),t+=a.length}return this.dispatchEvent(new CustomEvent("data",{detail:{incoming:e.length,outgoing:t}})),t}catch(t){throw this.log("handleData: error processing data:",t),t}}handleError(e){if(!this.active){this.log("handleError: handler not active, ignoring error");return}e.message?.includes("ECONNRESET")?this.log("handleError: client disconnected (ECONNRESET) - normal behavior"):e.message?.includes("Idle timeout")?this.log("handleError: connection idle timeout"):this.log("handleError:",e),this.active=!1,this.dispatchEvent(new CustomEvent("error",{detail:e})),this.detach(!0)}handleClose(){this.log("handleClose: socket closed"),this.active=!1,this.dispatchEvent(new CustomEvent("close")),this.detach(!1)}inspectData(e,t){if(this.inspect){console.log("-".repeat(75)),console.log(e==="incoming"?"-> incoming":"<- outgoing",t.length,"bytes");for(let i=0;i<t.length;i+=16){let r=Math.min(16,t.length-i),n="";for(let o=0;o<16;o++)if(o<r){let l=t[i+o];n+=l.toString(16).padStart(2,"0")+" "}else n+=" ";let a="";for(let o=0;o<r;o++){let l=t[i+o];a+=l>=32&&l<=126?String.fromCharCode(l):"."}console.log(`${i.toString(16).padStart(8,"0")} ${n} ${a}`)}}}};u.nextHandlerId=1;var f=u,d=class extends EventTarget{constructor(e){super();this.server=null;this.active=!1;this.handlers=new Set;this.db=e.db,e.path?this.path=e.path:(typeof e.port=="number"?this.port=e.port??e.port:this.port=5432,this.host=e.host||"127.0.0.1"),this.inspect=e.inspect??!1,this.debug=e.debug??!1,this.idleTimeout=e.idleTimeout??0,this.maxConnections=e.maxConnections??1,this.queryQueue=new p(this.db,this.debug),this.log(`constructor: created server on ${this.getServerConn()}`),this.log(`constructor: max connections: ${this.maxConnections}`),this.idleTimeout>0&&this.log(`constructor: idle timeout: ${this.idleTimeout}ms`)}log(e,...t){this.debug&&console.log(`[PGLiteSocketServer] ${e}`,...t)}async start(){if(this.log(`start: starting server on ${this.getServerConn()}`),this.server)throw new Error("Socket server already started");return await this.db.waitReady,this.active=!0,this.server=(0,b.createServer)(e=>{setImmediate(()=>this.handleConnection(e))}),this.server.maxConnections=this.maxConnections,new Promise((e,t)=>{if(!this.server)return t(new Error("Server not initialized"));if(this.server.on("error",i=>{this.log("start: server error:",i),this.dispatchEvent(new CustomEvent("error",{detail:i})),this.active||t(i)}),this.path)this.server.listen(this.path,()=>{this.log(`start: server listening on ${this.getServerConn()}`),this.dispatchEvent(new CustomEvent("listening",{detail:{path:this.path}})),e()});else{let i=this.server;i.listen(this.port,this.host,()=>{let r=i.address();if(r===null||typeof r!="object")throw Error("Expected address info");this.port=r.port,this.log(`start: server listening on ${this.getServerConn()}`),this.dispatchEvent(new CustomEvent("listening",{detail:{port:this.port,host:this.host}})),e()})}})}getServerConn(){return this.path?this.path:`${this.host}:${this.port}`}async stop(){this.log("stop: stopping server"),this.active=!1,this.log(`stop: detaching ${this.handlers.size} handlers`);for(let e of this.handlers)e.detach(!0);return this.handlers.clear(),this.server?new Promise(e=>{if(!this.server)return e();this.server.close(()=>{this.log("stop: server closed"),this.server=null,this.dispatchEvent(new CustomEvent("close")),e()})}):(this.log("stop: server not running, nothing to do"),Promise.resolve())}async handleConnection(e){let t={clientAddress:e.remoteAddress||"unknown",clientPort:e.remotePort||0};if(this.log(`handleConnection: new connection from ${t.clientAddress}:${t.clientPort}`),this.log(`handleConnection: active connections: ${this.handlers.size}, queued queries: ${this.queryQueue.getQueueLength()}`),!this.active){this.log("handleConnection: server not active, closing connection");try{e.end()}catch(r){this.log("handleConnection: error closing socket:",r)}return}if(this.handlers.size>=this.maxConnections){this.log("handleConnection: max connections reached, rejecting"),e.write(Buffer.from(`Too many connections
`)),e.end();return}let i=new f({queryQueue:this.queryQueue,closeOnDetach:!0,inspect:this.inspect,debug:this.debug,idleTimeout:this.idleTimeout});this.handlers.add(i),i.addEventListener("error",r=>{let n=r.detail;n?.message?.includes("ECONNRESET")?this.log(`handler #${i.handlerId}: client disconnected (ECONNRESET)`):n?.message?.includes("Idle timeout")?this.log(`handler #${i.handlerId}: idle timeout`):this.log(`handler #${i.handlerId}: error:`,n)}),i.addEventListener("close",()=>{this.log(`handler #${i.handlerId}: closed`),this.handlers.delete(i),this.log(`handleConnection: active connections: ${this.handlers.size}`)});try{await i.attach(e),this.dispatchEvent(new CustomEvent("connection",{detail:t}))}catch(r){this.log("handleConnection: error attaching socket:",r),this.handlers.delete(i),this.dispatchEvent(new CustomEvent("error",{detail:r}));try{e.end()}catch(n){this.log("handleConnection: error closing socket:",n)}}}getStats(){return{activeConnections:this.handlers.size,queuedQueries:this.queryQueue.getQueueLength(),maxConnections:this.maxConnections}}};var w=require("util"),E=require("child_process"),h=(0,w.parseArgs)({options:{db:{type:"string",short:"d",default:"memory://",help:"Database path (relative or absolute). Use memory:// for in-memory database."},port:{type:"string",short:"p",default:"5432",help:"Port to listen on"},host:{type:"string",short:"h",default:"127.0.0.1",help:"Host to bind to"},path:{type:"string",short:"u",default:void 0,help:"unix socket to bind to. Takes precedence over host:port"},debug:{type:"string",short:"v",default:"0",help:"Debug level (0-5)"},extensions:{type:"string",short:"e",default:void 0,help:"Comma-separated list of extensions to load (e.g., vector,pgcrypto)"},run:{type:"string",short:"r",default:void 0,help:"Command to run after server starts"},"include-database-url":{type:"boolean",default:!1,help:"Include DATABASE_URL in the environment of the subprocess"},"shutdown-timeout":{type:"string",default:"5000",help:"Timeout in milliseconds for graceful subprocess shutdown (default: 5000)"},"max-connections":{type:"string",short:"m",default:"1",help:"Maximum concurrent connections (default: 1)"},help:{type:"boolean",short:"?",default:!1,help:"Show help"}}}),C=`PGlite Socket Server
"use strict";var b=require("@electric-sql/pglite");var v=require("net");var m=class{constructor(i,e=!1){this.queue=[];this.processing=!1;this.lastHandlerId=null;this.db=i,this.debug=e}log(i,...e){this.debug&&console.log(`[QueryQueueManager] ${i}`,...e)}async enqueue(i,e,t){return new Promise((s,r)=>{let n={handlerId:i,message:e,resolve:s,reject:r,timestamp:Date.now(),onData:t};this.queue.push(n),this.log(`enqueued query from handler #${i}, queue size: ${this.queue.length}`),this.processing||this.processQueue()})}async processQueue(){if(!(this.processing||this.queue.length===0)){for(this.processing=!0;this.queue.length>0;){let i;if(this.db.isInTransaction()&&this.lastHandlerId){let s=this.queue.findIndex(r=>r.handlerId===this.lastHandlerId);s===-1?(this.log("transaction started, but no query from the same handler id found in queue",this.lastHandlerId),i=null):i=this.queue.splice(s,1)[0]}else i=this.queue.shift();if(!i)break;let e=Date.now()-i.timestamp;this.log(`processing query from handler #${i.handlerId} (waited ${e}ms)`);let t=0;try{await this.db.runExclusive(async()=>await this.db.execProtocolRawStream(i.message,{onRawData:s=>{t+=s.length,i.onData(s)}}))}catch(s){this.log(`query from handler #${i.handlerId} failed:`,s),i.reject(s);return}this.log(`query from handler #${i.handlerId} completed, ${t} bytes`),this.lastHandlerId=i.handlerId,i.resolve(t)}this.processing=!1,this.log("queue processing complete, queue length is",this.queue.length)}}getQueueLength(){return this.queue.length}clearQueueForHandler(i){let e=this.queue.length;this.queue=this.queue.filter(s=>s.handlerId===i?(s.reject(new Error("Handler disconnected")),!1):!0);let t=e-this.queue.length;t>0&&this.log(`cleared ${t} queries for handler #${i}`)}async clearTransactionIfNeeded(i){this.db.isInTransaction()&&this.lastHandlerId===i&&(await this.db.exec("ROLLBACK"),this.lastHandlerId=null,await this.processQueue())}},u=class u extends EventTarget{constructor(e){super();this.socket=null;this.active=!1;this.messageBuffer=Buffer.alloc(0);this.lastActivityTime=Date.now();this.queryQueue=e.queryQueue,this.closeOnDetach=e.closeOnDetach??!1,this.inspect=e.inspect??!1,this.debug=e.debug??!1,this.idleTimeout=e.idleTimeout??0,this.id=u.nextHandlerId++,this.log("constructor: created new handler")}get handlerId(){return this.id}log(e,...t){this.debug&&console.log(`[PGLiteSocketHandler#${this.id}] ${e}`,...t)}async attach(e){if(this.log(`attach: attaching socket from ${e.remoteAddress}:${e.remotePort}`),this.socket)throw new Error("Socket already attached");return this.socket=e,this.active=!0,this.lastActivityTime=Date.now(),e.setNoDelay(!0),this.idleTimeout>0&&this.resetIdleTimer(),this.log("attach: setting up socket event handlers"),e.on("data",t=>{this.lastActivityTime=Date.now(),this.resetIdleTimer(),setImmediate(async()=>{try{await this.handleData(t)}catch(s){this.log("socket on data error: ",s),this.handleError(s)}})}),e.on("error",t=>{setImmediate(()=>this.handleError(t))}),e.on("close",()=>{setImmediate(()=>this.handleClose())}),this.log("attach: socket handler ready"),this}resetIdleTimer(){this.idleTimeout<=0||(this.idleTimer&&clearTimeout(this.idleTimer),this.idleTimer=setTimeout(()=>{let e=Date.now()-this.lastActivityTime;this.log(`idle timeout after ${e}ms`),this.handleError(new Error("Idle timeout"))},this.idleTimeout))}async detach(e){if(this.log(`detach: detaching socket, close=${e??this.closeOnDetach}`),this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=void 0),this.queryQueue.clearQueueForHandler(this.id),await this.queryQueue.clearTransactionIfNeeded(this.id),!this.socket)return this.log("detach: no socket attached, nothing to do"),this;if(this.socket.removeAllListeners("data"),this.socket.removeAllListeners("error"),this.socket.removeAllListeners("close"),(e??this.closeOnDetach)&&this.socket.writable){this.log("detach: closing socket");try{this.socket.end(),this.socket.destroy()}catch(t){this.log("detach: error closing socket:",t)}}return this.socket=null,this.active=!1,this.messageBuffer=Buffer.alloc(0),this.log("detach: handler cleaned up"),this}get isAttached(){return this.socket!==null}async handleData(e){if(!this.socket||!this.active)return this.log("handleData: no active socket, ignoring data"),0;this.log(`handleData: received ${e.length} bytes`),this.messageBuffer=Buffer.concat([this.messageBuffer,e]),this.inspectData("incoming",e);try{let t=0;for(;this.messageBuffer.length>0;){let s=0,r=!1;if(this.messageBuffer.length>=4){let o=this.messageBuffer.readInt32BE(0);if(this.messageBuffer.length>=8){let a=this.messageBuffer.readInt32BE(4);(a===196608||a===196608)&&(s=o,r=this.messageBuffer.length>=s)}!r&&this.messageBuffer.length>=5&&(s=1+this.messageBuffer.readInt32BE(1),r=this.messageBuffer.length>=s)}if(!r||s===0){this.log(`handleData: incomplete message, buffering ${this.messageBuffer.length} bytes`);break}let n=this.messageBuffer.slice(0,s);if(this.messageBuffer=this.messageBuffer.slice(s),this.log(`handleData: processing message of ${n.length} bytes`),!this.active||!this.socket){this.log("handleData: socket no longer active, stopping processing");break}let c;if(await this.queryQueue.enqueue(this.id,new Uint8Array(n),o=>{this.log(`handleData: received ${o.length} bytes from PGlite`),this.inspectData("outgoing",o),o.length>0&&this.socket&&this.socket.writable&&this.active&&(this.log("handleData: writing response to socket"),this.socket?.writable?this.socket.write(Buffer.from(o),a=>{a?(this.log("handleData: error writing to socket:",a),c=a):this.log(`handleData: socket sent: ${o.length} bytes`)}):this.log("handleData: socket no longer writable")),t+=o.length}),c)throw c}return this.dispatchEvent(new CustomEvent("data",{detail:{incoming:e.length,outgoing:t}})),t}catch(t){throw this.log("handleData: error processing data:",t),t}}handleError(e){if(!this.active){this.log("handleError: handler not active, ignoring error");return}e.message?.includes("ECONNRESET")?this.log("handleError: client disconnected (ECONNRESET) - normal behavior"):e.message?.includes("Idle timeout")?this.log("handleError: connection idle timeout"):this.log("handleError:",e),this.active=!1,this.dispatchEvent(new CustomEvent("error",{detail:e})),this.detach(!0)}handleClose(){this.log("handleClose: socket closed"),this.active=!1,this.dispatchEvent(new CustomEvent("close")),this.detach(!1)}inspectData(e,t){if(this.inspect){console.log("-".repeat(75)),console.log(e==="incoming"?"-> incoming":"<- outgoing",t.length,"bytes");for(let s=0;s<t.length;s+=16){let r=Math.min(16,t.length-s),n="";for(let o=0;o<16;o++)if(o<r){let a=t[s+o];n+=a.toString(16).padStart(2,"0")+" "}else n+=" ";let c="";for(let o=0;o<r;o++){let a=t[s+o];c+=a>=32&&a<=126?String.fromCharCode(a):"."}console.log(`${s.toString(16).padStart(8,"0")} ${n} ${c}`)}}}};u.nextHandlerId=1;var p=u,d=class extends EventTarget{constructor(e){super();this.server=null;this.active=!1;this.handlers=new Set;this.db=e.db,e.path?this.path=e.path:(typeof e.port=="number"?this.port=e.port??e.port:this.port=5432,this.host=e.host||"127.0.0.1"),this.inspect=e.inspect??!1,this.debug=e.debug??!1,this.idleTimeout=e.idleTimeout??0,this.maxConnections=e.maxConnections??1,this.queryQueue=new m(this.db,this.debug),this.log(`constructor: created server on ${this.getServerConn()}`),this.log(`constructor: max connections: ${this.maxConnections}`),this.idleTimeout>0&&this.log(`constructor: idle timeout: ${this.idleTimeout}ms`)}log(e,...t){this.debug&&console.log(`[PGLiteSocketServer] ${e}`,...t)}async start(){if(this.log(`start: starting server on ${this.getServerConn()}`),this.server)throw new Error("Socket server already started");return await this.db.waitReady,this.active=!0,this.server=(0,v.createServer)(e=>{setImmediate(()=>this.handleConnection(e))}),this.server.maxConnections=this.maxConnections,new Promise((e,t)=>{if(!this.server)return t(new Error("Server not initialized"));if(this.server.on("error",s=>{this.log("start: server error:",s),this.dispatchEvent(new CustomEvent("error",{detail:s})),this.active||t(s)}),this.path)this.server.listen(this.path,()=>{this.log(`start: server listening on ${this.getServerConn()}`),this.dispatchEvent(new CustomEvent("listening",{detail:{path:this.path}})),e()});else{let s=this.server;s.listen(this.port,this.host,()=>{let r=s.address();if(r===null||typeof r!="object")throw Error("Expected address info");this.port=r.port,this.log(`start: server listening on ${this.getServerConn()}`),this.dispatchEvent(new CustomEvent("listening",{detail:{port:this.port,host:this.host}})),e()})}})}getServerConn(){return this.path?this.path:`${this.host}:${this.port}`}async stop(){this.log("stop: stopping server"),this.active=!1,this.log(`stop: detaching ${this.handlers.size} handlers`);for(let e of this.handlers)e.detach(!0);return this.handlers.clear(),this.server?new Promise(e=>{if(!this.server)return e();this.server.close(()=>{this.log("stop: server closed"),this.server=null,this.dispatchEvent(new CustomEvent("close")),e()})}):(this.log("stop: server not running, nothing to do"),Promise.resolve())}async handleConnection(e){let t={clientAddress:e.remoteAddress||"unknown",clientPort:e.remotePort||0};if(this.log(`handleConnection: new connection from ${t.clientAddress}:${t.clientPort}`),this.log(`handleConnection: active connections: ${this.handlers.size}, queued queries: ${this.queryQueue.getQueueLength()}`),!this.active){this.log("handleConnection: server not active, closing connection");try{e.end()}catch(r){this.log("handleConnection: error closing socket:",r)}return}if(this.handlers.size>=this.maxConnections){this.log("handleConnection: max connections reached, rejecting"),e.write(Buffer.from(`Too many connections
`)),e.end();return}let s=new p({queryQueue:this.queryQueue,closeOnDetach:!0,inspect:this.inspect,debug:this.debug,idleTimeout:this.idleTimeout});this.handlers.add(s),s.addEventListener("error",r=>{let n=r.detail;n?.message?.includes("ECONNRESET")?this.log(`handler #${s.handlerId}: client disconnected (ECONNRESET)`):n?.message?.includes("Idle timeout")?this.log(`handler #${s.handlerId}: idle timeout`):this.log(`handler #${s.handlerId}: error:`,n)}),s.addEventListener("close",()=>{this.log(`handler #${s.handlerId}: closed`),this.handlers.delete(s),this.log(`handleConnection: active connections: ${this.handlers.size}`)});try{await s.attach(e),this.dispatchEvent(new CustomEvent("connection",{detail:t}))}catch(r){this.log("handleConnection: error attaching socket:",r),this.handlers.delete(s),this.dispatchEvent(new CustomEvent("error",{detail:r}));try{e.end()}catch(n){this.log("handleConnection: error closing socket:",n)}}}getStats(){return{activeConnections:this.handlers.size,queuedQueries:this.queryQueue.getQueueLength(),maxConnections:this.maxConnections}}};var y=require("util"),w=require("child_process"),l=(0,y.parseArgs)({options:{db:{type:"string",short:"d",default:"memory://",help:"Database path (relative or absolute). Use memory:// for in-memory database."},port:{type:"string",short:"p",default:"5432",help:"Port to listen on"},host:{type:"string",short:"h",default:"127.0.0.1",help:"Host to bind to"},path:{type:"string",short:"u",default:void 0,help:"unix socket to bind to. Takes precedence over host:port"},debug:{type:"string",short:"v",default:"0",help:"Debug level (0-5)"},extensions:{type:"string",short:"e",default:void 0,help:"Comma-separated list of extensions to load (e.g., vector,pgcrypto,postgis etc.)"},run:{type:"string",short:"r",default:void 0,help:"Command to run after server starts"},"include-database-url":{type:"boolean",default:!1,help:"Include DATABASE_URL in the environment of the subprocess"},"shutdown-timeout":{type:"string",default:"5000",help:"Timeout in milliseconds for graceful subprocess shutdown (default: 5000)"},"max-connections":{type:"string",short:"m",default:"1",help:"Maximum concurrent connections (default: 1)"},help:{type:"boolean",short:"?",default:!1,help:"Show help"}}}),x=`PGlite Socket Server
Usage: pglite-server [options]

@@ -19,4 +19,4 @@

-m, --max-connections=N Maximum concurrent connections (default is no concurrency: 1)
`,g=class{constructor(s){this.db=null;this.server=null;this.subprocessManager=null;this.config=s}static parseConfig(){let s=h.values.extensions;return{dbPath:h.values.db,port:parseInt(h.values.port,10),host:h.values.host,path:h.values.path,debugLevel:parseInt(h.values.debug,10),extensionNames:s?s.split(",").map(e=>e.trim()):void 0,runCommand:h.values.run,includeDatabaseUrl:h.values["include-database-url"],shutdownTimeout:parseInt(h.values["shutdown-timeout"],10),maxConnections:parseInt(h.values["max-connections"],10)}}createDatabaseUrl(){let{host:s,port:e,path:t}=this.config;if(t){let i=t.endsWith("/.s.PGSQL.5432")?t.slice(0,-13):t;return`postgresql://postgres:postgres@/postgres?host=${encodeURIComponent(i)}`}else return`postgresql://postgres:postgres@${s}:${e}/postgres`}async importExtensions(){if(!this.config.extensionNames?.length)return;let s={},e=["vector","live","pg_hashids","pg_ivm","pg_uuidv7","pgtap"];for(let t of this.config.extensionNames){let i=null;try{if(t.includes(":")){let[r,n]=t.split(":");if(!r||!n)throw new Error(`Invalid extension format '${t}'. Expected: package/path:exportedName`);i=(await import(r))[n],i&&(s[n]=i,console.log(`Imported extension '${n}' from '${r}'`))}else if(e.includes(t))i=(await import(`@electric-sql/pglite/${t}`))[t],i&&(s[t]=i,console.log(`Imported extension: ${t}`));else{try{i=(await import(`@electric-sql/pglite/contrib/${t}`))[t]}catch{i=(await import(`@electric-sql/pglite-${t}`))[t]}i&&(s[t]=i,console.log(`Imported extension: ${t}`))}}catch(r){throw console.error(`Failed to import extension '${t}':`,r),new Error(`Failed to import extension '${t}'`)}}return Object.keys(s).length>0?s:void 0}async initializeDatabase(){console.log(`Initializing PGLite with database: ${this.config.dbPath}`),console.log(`Debug level: ${this.config.debugLevel}`);let s=await this.importExtensions();this.db=new y.PGlite(this.config.dbPath,{debug:this.config.debugLevel,extensions:s}),await this.db.waitReady,console.log("PGlite database initialized")}setupServerEventHandlers(){if(!this.server||!this.subprocessManager)throw new Error("Server or subprocess manager not initialized");this.server.addEventListener("listening",s=>{let e=s.detail;if(console.log(`PGLiteSocketServer listening on ${JSON.stringify(e)}`),this.config.runCommand&&this.subprocessManager){let t=this.createDatabaseUrl();this.subprocessManager.spawn(this.config.runCommand,t,this.config.includeDatabaseUrl)}}),this.server.addEventListener("connection",s=>{let{clientAddress:e,clientPort:t}=s.detail;console.log(`Client connected from ${e}:${t}`)}),this.server.addEventListener("error",s=>{let e=s.detail;console.error("Socket server error:",e)})}setupSignalHandlers(){process.on("SIGINT",()=>this.shutdown()),process.on("SIGTERM",()=>this.shutdown())}async start(){try{if(await this.initializeDatabase(),!this.db)throw new Error("Database initialization failed");this.server=new d({db:this.db,port:this.config.port,host:this.config.host,path:this.config.path,inspect:this.config.debugLevel>0,maxConnections:this.config.maxConnections}),this.subprocessManager=new v(s=>{this.shutdown(s)}),this.setupServerEventHandlers(),this.setupSignalHandlers(),await this.server.start()}catch(s){throw console.error("Failed to start PGLiteSocketServer:",s),s}}async shutdown(s=0){console.log(`
Shutting down PGLiteSocketServer...`),this.subprocessManager&&this.subprocessManager.terminate(this.config.shutdownTimeout),this.server&&await this.server.stop(),this.db&&await this.db.close(),console.log("Server stopped"),process.exit(s)}},v=class{constructor(s){this.childProcess=null;this.onExit=s}get process(){return this.childProcess}spawn(s,e,t){console.log(`Running command: ${s}`);let i={...process.env};t&&(i.DATABASE_URL=e,console.log(`Setting DATABASE_URL=${e}`));let r=s.trim().split(/\s+/);this.childProcess=(0,E.spawn)(r[0],r.slice(1),{env:i,stdio:"inherit"}),this.childProcess.on("error",n=>{console.error("Error running command:",n),console.log("Subprocess failed to start, shutting down..."),this.onExit(1)}),this.childProcess.on("close",n=>{console.log(`Command exited with code ${n}`),this.childProcess=null,n!==null&&n!==0&&(console.log(`Child process failed with exit code ${n}, shutting down...`),this.onExit(n))})}terminate(s){this.childProcess&&(console.log("Terminating child process..."),this.childProcess.kill("SIGTERM"),setTimeout(()=>{this.childProcess&&!this.childProcess.killed&&(console.log("Force killing child process..."),this.childProcess.kill("SIGKILL"))},s))}};async function S(){h.values.help&&(console.log(C),process.exit(0));try{let c=g.parseConfig();await new g(c).start()}catch(c){console.error("Unhandled error:",c),process.exit(1)}}S();
`,g=class{constructor(i){this.db=null;this.server=null;this.subprocessManager=null;this.config=i}static parseConfig(){let i=l.values.extensions;return{dbPath:l.values.db,port:parseInt(l.values.port,10),host:l.values.host,path:l.values.path,debugLevel:parseInt(l.values.debug,10),extensionNames:i?i.split(",").map(e=>e.trim()):void 0,runCommand:l.values.run,includeDatabaseUrl:l.values["include-database-url"],shutdownTimeout:parseInt(l.values["shutdown-timeout"],10),maxConnections:parseInt(l.values["max-connections"],10)}}createDatabaseUrl(){let{host:i,port:e,path:t}=this.config;if(t){let s=t.endsWith("/.s.PGSQL.5432")?t.slice(0,-13):t;return`postgresql://postgres:postgres@/postgres?host=${encodeURIComponent(s)}`}else return`postgresql://postgres:postgres@${i}:${e}/postgres`}async importExtensions(){if(!this.config.extensionNames?.length)return;let i={},e=["vector","live","pg_hashids","pg_ivm","pg_uuidv7","pgtap","age","pg_textsearch"];for(let t of this.config.extensionNames){let s=null;try{if(t.includes(":")){let[r,n]=t.split(":");if(!r||!n)throw new Error(`Invalid extension format '${t}'. Expected: package/path:exportedName`);s=(await import(r))[n],s&&(i[n]=s,console.log(`Imported extension '${n}' from '${r}'`))}else if(e.includes(t))s=(await import(`@electric-sql/pglite/${t}`))[t],s&&(i[t]=s,console.log(`Imported extension: ${t}`));else{try{s=(await import(`@electric-sql/pglite/contrib/${t}`))[t]}catch{s=(await import(`@electric-sql/pglite-${t}`))[t]}s&&(i[t]=s,console.log(`Imported extension: ${t}`))}}catch(r){throw console.error(`Failed to import extension '${t}':`,r),new Error(`Failed to import extension '${t}'`)}}return Object.keys(i).length>0?i:void 0}async initializeDatabase(){console.log(`Initializing PGLite with database: ${this.config.dbPath}`),console.log(`Debug level: ${this.config.debugLevel}`);let i=await this.importExtensions();this.db=new b.PGlite(this.config.dbPath,{debug:this.config.debugLevel,extensions:i}),await this.db.waitReady,console.log("PGlite database initialized")}setupServerEventHandlers(){if(!this.server||!this.subprocessManager)throw new Error("Server or subprocess manager not initialized");this.server.addEventListener("listening",i=>{let e=i.detail;if(console.log(`PGLiteSocketServer listening on ${JSON.stringify(e)}`),this.config.runCommand&&this.subprocessManager){let t=this.createDatabaseUrl();this.subprocessManager.spawn(this.config.runCommand,t,this.config.includeDatabaseUrl)}}),this.server.addEventListener("connection",i=>{let{clientAddress:e,clientPort:t}=i.detail;console.log(`Client connected from ${e}:${t}`)}),this.server.addEventListener("error",i=>{let e=i.detail;console.error("Socket server error:",e)})}setupSignalHandlers(){process.on("SIGINT",()=>this.shutdown()),process.on("SIGTERM",()=>this.shutdown())}async start(){try{if(await this.initializeDatabase(),!this.db)throw new Error("Database initialization failed");this.server=new d({db:this.db,port:this.config.port,host:this.config.host,path:this.config.path,inspect:this.config.debugLevel>0,maxConnections:this.config.maxConnections}),this.subprocessManager=new f(i=>{this.shutdown(i)}),this.setupServerEventHandlers(),this.setupSignalHandlers(),await this.server.start()}catch(i){throw console.error("Failed to start PGLiteSocketServer:",i),i}}async shutdown(i=0){console.log(`
Shutting down PGLiteSocketServer...`),this.subprocessManager&&this.subprocessManager.terminate(this.config.shutdownTimeout),this.server&&await this.server.stop(),this.db&&await this.db.close(),console.log("Server stopped"),process.exit(i)}},f=class{constructor(i){this.childProcess=null;this.onExit=i}get process(){return this.childProcess}spawn(i,e,t){console.log(`Running command: ${i}`);let s={...process.env};t&&(s.DATABASE_URL=e,console.log(`Setting DATABASE_URL=${e}`));let r=i.trim().split(/\s+/);this.childProcess=(0,w.spawn)(r[0],r.slice(1),{env:s,stdio:"inherit"}),this.childProcess.on("error",n=>{console.error("Error running command:",n),console.log("Subprocess failed to start, shutting down..."),this.onExit(1)}),this.childProcess.on("close",n=>{console.log(`Command exited with code ${n}`),this.childProcess=null,n!==null&&n!==0&&(console.log(`Child process failed with exit code ${n}, shutting down...`),this.onExit(n))})}terminate(i){this.childProcess&&(console.log("Terminating child process..."),this.childProcess.kill("SIGTERM"),setTimeout(()=>{this.childProcess&&!this.childProcess.killed&&(console.log("Force killing child process..."),this.childProcess.kill("SIGKILL"))},i))}};async function C(){l.values.help&&(console.log(x),process.exit(0));try{let h=g.parseConfig();await new g(h).start()}catch(h){console.error("Unhandled error:",h),process.exit(1)}}C();
//# sourceMappingURL=server.cjs.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../src/scripts/server.ts","../../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { PGlite, DebugLevel } from '@electric-sql/pglite'\nimport type { Extension, Extensions } from '@electric-sql/pglite'\nimport { PGLiteSocketServer } from '../index'\nimport { parseArgs } from 'node:util'\nimport { spawn, ChildProcess } from 'node:child_process'\n\n// Define command line argument options\nconst args = parseArgs({\n options: {\n db: {\n type: 'string',\n short: 'd',\n default: 'memory://',\n help: 'Database path (relative or absolute). Use memory:// for in-memory database.',\n },\n port: {\n type: 'string',\n short: 'p',\n default: '5432',\n help: 'Port to listen on',\n },\n host: {\n type: 'string',\n short: 'h',\n default: '127.0.0.1',\n help: 'Host to bind to',\n },\n path: {\n type: 'string',\n short: 'u',\n default: undefined,\n help: 'unix socket to bind to. Takes precedence over host:port',\n },\n debug: {\n type: 'string',\n short: 'v',\n default: '0',\n help: 'Debug level (0-5)',\n },\n extensions: {\n type: 'string',\n short: 'e',\n default: undefined,\n help: 'Comma-separated list of extensions to load (e.g., vector,pgcrypto)',\n },\n run: {\n type: 'string',\n short: 'r',\n default: undefined,\n help: 'Command to run after server starts',\n },\n 'include-database-url': {\n type: 'boolean',\n default: false,\n help: 'Include DATABASE_URL in the environment of the subprocess',\n },\n 'shutdown-timeout': {\n type: 'string',\n default: '5000',\n help: 'Timeout in milliseconds for graceful subprocess shutdown (default: 5000)',\n },\n 'max-connections': {\n type: 'string',\n short: 'm',\n default: '1',\n help: 'Maximum concurrent connections (default: 1)',\n },\n help: {\n type: 'boolean',\n short: '?',\n default: false,\n help: 'Show help',\n },\n },\n})\n\nconst help = `PGlite Socket Server\nUsage: pglite-server [options]\n\nOptions:\n -d, --db=PATH Database path (default: memory://)\n -p, --port=PORT Port to listen on (default: 5432)\n -h, --host=HOST Host to bind to (default: 127.0.0.1)\n -u, --path=UNIX Unix socket to bind to (default: undefined). Takes precedence over host:port\n -v, --debug=LEVEL Debug level 0-5 (default: 0)\n -e, --extensions=LIST Comma-separated list of extensions to load\n Formats: vector, pgcrypto (built-in/contrib)\n @org/package/path:exportedName (npm package)\n -r, --run=COMMAND Command to run after server starts\n --include-database-url Include DATABASE_URL in subprocess environment\n --shutdown-timeout=MS Timeout for graceful subprocess shutdown in ms (default: 5000)\n -m, --max-connections=N Maximum concurrent connections (default is no concurrency: 1)\n`\n\ninterface ServerConfig {\n dbPath: string\n port: number\n host: string\n path?: string\n debugLevel: DebugLevel\n extensionNames?: string[]\n runCommand?: string\n includeDatabaseUrl: boolean\n shutdownTimeout: number\n maxConnections: number\n}\n\nclass PGLiteServerRunner {\n private config: ServerConfig\n private db: PGlite | null = null\n private server: PGLiteSocketServer | null = null\n private subprocessManager: SubprocessManager | null = null\n\n constructor(config: ServerConfig) {\n this.config = config\n }\n\n static parseConfig(): ServerConfig {\n const extensionsArg = args.values.extensions as string | undefined\n return {\n dbPath: args.values.db as string,\n port: parseInt(args.values.port as string, 10),\n host: args.values.host as string,\n path: args.values.path as string,\n debugLevel: parseInt(args.values.debug as string, 10) as DebugLevel,\n extensionNames: extensionsArg\n ? extensionsArg.split(',').map((e) => e.trim())\n : undefined,\n runCommand: args.values.run as string,\n includeDatabaseUrl: args.values['include-database-url'] as boolean,\n shutdownTimeout: parseInt(args.values['shutdown-timeout'] as string, 10),\n maxConnections: parseInt(args.values['max-connections'] as string, 10),\n }\n }\n\n private createDatabaseUrl(): string {\n const { host, port, path } = this.config\n\n if (path) {\n // Unix socket connection\n const socketDir = path.endsWith('/.s.PGSQL.5432')\n ? path.slice(0, -13)\n : path\n return `postgresql://postgres:postgres@/postgres?host=${encodeURIComponent(socketDir)}`\n } else {\n // TCP connection\n return `postgresql://postgres:postgres@${host}:${port}/postgres`\n }\n }\n\n private async importExtensions(): Promise<Extensions | undefined> {\n if (!this.config.extensionNames?.length) {\n return undefined\n }\n\n const extensions: Extensions = {}\n\n // Built-in extensions that are not in contrib\n const builtInExtensions = [\n 'vector',\n 'live',\n 'pg_hashids',\n 'pg_ivm',\n 'pg_uuidv7',\n 'pgtap',\n ]\n\n for (const name of this.config.extensionNames) {\n let ext: Extension | null = null\n\n try {\n // Check if this is a custom package path (contains ':')\n // Format: @org/package/path:exportedName or package/path:exportedName\n if (name.includes(':')) {\n const [packagePath, exportName] = name.split(':')\n if (!packagePath || !exportName) {\n throw new Error(\n `Invalid extension format '${name}'. Expected: package/path:exportedName`,\n )\n }\n const mod = await import(packagePath)\n ext = mod[exportName] as Extension\n if (ext) {\n extensions[exportName] = ext\n console.log(\n `Imported extension '${exportName}' from '${packagePath}'`,\n )\n }\n } else if (builtInExtensions.includes(name)) {\n // Built-in extension (e.g., @electric-sql/pglite/vector)\n const mod = await import(`@electric-sql/pglite/${name}`)\n ext = mod[name] as Extension\n if (ext) {\n extensions[name] = ext\n console.log(`Imported extension: ${name}`)\n }\n } else {\n // Try contrib first (e.g., @electric-sql/pglite/contrib/pgcrypto)\n try {\n const mod = await import(`@electric-sql/pglite/contrib/${name}`)\n ext = mod[name] as Extension\n } catch {\n // Fall back to external package (e.g., @electric-sql/pglite-<extension>)\n const mod = await import(`@electric-sql/pglite-${name}`)\n ext = mod[name] as Extension\n }\n if (ext) {\n extensions[name] = ext\n console.log(`Imported extension: ${name}`)\n }\n }\n } catch (error) {\n console.error(`Failed to import extension '${name}':`, error)\n throw new Error(`Failed to import extension '${name}'`)\n }\n }\n\n return Object.keys(extensions).length > 0 ? extensions : undefined\n }\n\n private async initializeDatabase(): Promise<void> {\n console.log(`Initializing PGLite with database: ${this.config.dbPath}`)\n console.log(`Debug level: ${this.config.debugLevel}`)\n\n const extensions = await this.importExtensions()\n\n this.db = new PGlite(this.config.dbPath, {\n debug: this.config.debugLevel,\n extensions,\n })\n await this.db.waitReady\n console.log('PGlite database initialized')\n }\n\n private setupServerEventHandlers(): void {\n if (!this.server || !this.subprocessManager) {\n throw new Error('Server or subprocess manager not initialized')\n }\n\n this.server.addEventListener('listening', (event) => {\n const detail = (\n event as CustomEvent<{ port: number; host: string } | { host: string }>\n ).detail\n console.log(`PGLiteSocketServer listening on ${JSON.stringify(detail)}`)\n\n // Run the command after server starts listening\n if (this.config.runCommand && this.subprocessManager) {\n const databaseUrl = this.createDatabaseUrl()\n this.subprocessManager.spawn(\n this.config.runCommand,\n databaseUrl,\n this.config.includeDatabaseUrl,\n )\n }\n })\n\n this.server.addEventListener('connection', (event) => {\n const { clientAddress, clientPort } = (\n event as CustomEvent<{ clientAddress: string; clientPort: number }>\n ).detail\n console.log(`Client connected from ${clientAddress}:${clientPort}`)\n })\n\n this.server.addEventListener('error', (event) => {\n const error = (event as CustomEvent<Error>).detail\n console.error('Socket server error:', error)\n })\n }\n\n private setupSignalHandlers(): void {\n process.on('SIGINT', () => this.shutdown())\n process.on('SIGTERM', () => this.shutdown())\n }\n\n async start(): Promise<void> {\n try {\n // Initialize database\n await this.initializeDatabase()\n\n if (!this.db) {\n throw new Error('Database initialization failed')\n }\n\n // Create and setup the socket server\n this.server = new PGLiteSocketServer({\n db: this.db,\n port: this.config.port,\n host: this.config.host,\n path: this.config.path,\n inspect: this.config.debugLevel > 0,\n maxConnections: this.config.maxConnections,\n })\n\n // Create subprocess manager\n this.subprocessManager = new SubprocessManager((exitCode) => {\n this.shutdown(exitCode)\n })\n\n // Setup event handlers\n this.setupServerEventHandlers()\n this.setupSignalHandlers()\n\n // Start the server\n await this.server.start()\n } catch (error) {\n console.error('Failed to start PGLiteSocketServer:', error)\n throw error\n }\n }\n\n async shutdown(exitCode: number = 0): Promise<void> {\n console.log('\\nShutting down PGLiteSocketServer...')\n\n // Terminate subprocess if running\n if (this.subprocessManager) {\n this.subprocessManager.terminate(this.config.shutdownTimeout)\n }\n\n // Stop server\n if (this.server) {\n await this.server.stop()\n }\n\n // Close database\n if (this.db) {\n await this.db.close()\n }\n\n console.log('Server stopped')\n process.exit(exitCode)\n }\n}\n\nclass SubprocessManager {\n private childProcess: ChildProcess | null = null\n private onExit: (code: number) => void\n\n constructor(onExit: (code: number) => void) {\n this.onExit = onExit\n }\n\n get process(): ChildProcess | null {\n return this.childProcess\n }\n\n spawn(\n command: string,\n databaseUrl: string,\n includeDatabaseUrl: boolean,\n ): void {\n console.log(`Running command: ${command}`)\n\n // Prepare environment variables\n const env = { ...process.env }\n if (includeDatabaseUrl) {\n env.DATABASE_URL = databaseUrl\n console.log(`Setting DATABASE_URL=${databaseUrl}`)\n }\n\n // Parse and spawn the command\n const commandParts = command.trim().split(/\\s+/)\n this.childProcess = spawn(commandParts[0], commandParts.slice(1), {\n env,\n stdio: 'inherit',\n })\n\n this.childProcess.on('error', (error) => {\n console.error('Error running command:', error)\n // If subprocess fails to start, shutdown the server\n console.log('Subprocess failed to start, shutting down...')\n this.onExit(1)\n })\n\n this.childProcess.on('close', (code) => {\n console.log(`Command exited with code ${code}`)\n this.childProcess = null\n\n // If child process exits with non-zero code, notify parent\n if (code !== null && code !== 0) {\n console.log(\n `Child process failed with exit code ${code}, shutting down...`,\n )\n this.onExit(code)\n }\n })\n }\n\n terminate(timeout: number): void {\n if (this.childProcess) {\n console.log('Terminating child process...')\n this.childProcess.kill('SIGTERM')\n\n // Give it a moment to exit gracefully, then force kill if needed\n setTimeout(() => {\n if (this.childProcess && !this.childProcess.killed) {\n console.log('Force killing child process...')\n this.childProcess.kill('SIGKILL')\n }\n }, timeout)\n }\n }\n}\n\n// Main execution\nasync function main() {\n // Show help and exit if requested\n if (args.values.help) {\n console.log(help)\n process.exit(0)\n }\n\n try {\n const config = PGLiteServerRunner.parseConfig()\n const serverRunner = new PGLiteServerRunner(config)\n await serverRunner.start()\n } catch (error) {\n console.error('Unhandled error:', error)\n process.exit(1)\n }\n}\n\n// Run the main function\nmain()\n","import type { PGlite } from '@electric-sql/pglite'\nimport { type Server, type Socket, createServer } from 'net'\n\n// Connection queue timeout in milliseconds\nexport const CONNECTION_QUEUE_TIMEOUT = 60000 // 60 seconds\n\n/**\n * Represents a queued query waiting for PGlite access\n */\ninterface QueuedQuery {\n handlerId: number\n message: Uint8Array\n resolve: (result: Uint8Array) => void\n reject: (error: Error) => void\n timestamp: number\n}\n\n/**\n * Global query queue manager\n * Ensures only one query executes at a time in PGlite\n */\nclass QueryQueueManager {\n private queue: QueuedQuery[] = []\n private processing = false\n private db: PGlite\n private debug: boolean\n private lastHandlerId: null | number = null\n\n constructor(db: PGlite, debug = false) {\n this.db = db\n this.debug = debug\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[QueryQueueManager] ${message}`, ...args)\n }\n }\n\n async enqueue(handlerId: number, message: Uint8Array): Promise<Uint8Array> {\n return new Promise((resolve, reject) => {\n const query: QueuedQuery = {\n handlerId,\n message,\n resolve,\n reject,\n timestamp: Date.now(),\n }\n\n this.queue.push(query)\n this.log(\n `enqueued query from handler #${handlerId}, queue size: ${this.queue.length}`,\n )\n\n // Process queue if not already processing\n if (!this.processing) {\n this.processQueue()\n }\n })\n }\n\n private async processQueue(): Promise<void> {\n if (this.processing || this.queue.length === 0) {\n return\n }\n\n this.processing = true\n\n while (this.queue.length > 0) {\n let query\n\n if (this.db.isInTransaction() && this.lastHandlerId) {\n const i = this.queue.findIndex(\n (q) => q.handlerId === this.lastHandlerId,\n )\n if (i === -1) {\n // we didn't find any other query from the same client!\n this.log(\n `transaction started, but no query from the same handler id found in queue`,\n this.lastHandlerId,\n )\n query = null\n } else {\n query = this.queue.splice(i, 1)[0]\n }\n } else {\n query = this.queue.shift()\n }\n if (!query) break\n\n const waitTime = Date.now() - query.timestamp\n this.log(\n `processing query from handler #${query.handlerId} (waited ${waitTime}ms)`,\n )\n\n try {\n // Execute the query with exclusive access to PGlite\n const result = await this.db.runExclusive(async () => {\n return await this.db.execProtocolRaw(query.message)\n })\n\n this.log(\n `query from handler #${query.handlerId} completed, ${result.length} bytes`,\n )\n this.lastHandlerId = query.handlerId\n query.resolve(result)\n } catch (error) {\n this.log(`query from handler #${query.handlerId} failed:`, error)\n query.reject(error as Error)\n }\n }\n\n this.processing = false\n this.log(`queue processing complete, queue length is`, this.queue.length)\n }\n\n getQueueLength(): number {\n return this.queue.length\n }\n\n clearQueueForHandler(handlerId: number): void {\n const before = this.queue.length\n this.queue = this.queue.filter((q) => {\n if (q.handlerId === handlerId) {\n q.reject(new Error('Handler disconnected'))\n return false\n }\n return true\n })\n const removed = before - this.queue.length\n if (removed > 0) {\n this.log(`cleared ${removed} queries for handler #${handlerId}`)\n }\n }\n\n async clearTransactionIfNeeded(handlerId: number): Promise<void> {\n if (this.db.isInTransaction() && this.lastHandlerId === handlerId) {\n await this.db.exec('ROLLBACK')\n this.lastHandlerId = null\n await this.processQueue()\n }\n }\n}\n\n/**\n * Options for creating a PGLiteSocketHandler\n */\nexport interface PGLiteSocketHandlerOptions {\n /** The query queue manager */\n queryQueue: QueryQueueManager\n /** Whether to close the socket when detached (default: false) */\n closeOnDetach?: boolean\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n /** Idle timeout in ms (0 to disable, default: 0) */\n idleTimeout?: number\n}\n\n/**\n * Handler for a single socket connection to PGlite\n * Each connection can remain open and send multiple queries\n */\nexport class PGLiteSocketHandler extends EventTarget {\n private queryQueue: QueryQueueManager\n private socket: Socket | null = null\n private active = false\n private closeOnDetach: boolean\n private inspect: boolean\n private debug: boolean\n private readonly id: number\n private messageBuffer: Buffer = Buffer.alloc(0)\n private idleTimer?: NodeJS.Timeout\n private idleTimeout: number\n private lastActivityTime: number = Date.now()\n\n // Static counter for generating unique handler IDs\n private static nextHandlerId = 1\n\n constructor(options: PGLiteSocketHandlerOptions) {\n super()\n this.queryQueue = options.queryQueue\n this.closeOnDetach = options.closeOnDetach ?? false\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.idleTimeout = options.idleTimeout ?? 0\n this.id = PGLiteSocketHandler.nextHandlerId++\n\n this.log('constructor: created new handler')\n }\n\n public get handlerId(): number {\n return this.id\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketHandler#${this.id}] ${message}`, ...args)\n }\n }\n\n public async attach(socket: Socket): Promise<PGLiteSocketHandler> {\n this.log(\n `attach: attaching socket from ${socket.remoteAddress}:${socket.remotePort}`,\n )\n\n if (this.socket) {\n throw new Error('Socket already attached')\n }\n\n this.socket = socket\n this.active = true\n this.lastActivityTime = Date.now()\n\n // Set up socket options\n socket.setNoDelay(true)\n\n // Set up idle timeout if configured\n if (this.idleTimeout > 0) {\n this.resetIdleTimer()\n }\n\n // Setup event handlers\n this.log(`attach: setting up socket event handlers`)\n\n socket.on('data', (data) => {\n this.lastActivityTime = Date.now()\n this.resetIdleTimer()\n\n setImmediate(async () => {\n try {\n await this.handleData(data)\n } catch (err) {\n this.log('socket on data error: ', err)\n this.handleError(err as Error)\n }\n })\n })\n\n socket.on('error', (err) => {\n setImmediate(() => this.handleError(err))\n })\n\n socket.on('close', () => {\n setImmediate(() => this.handleClose())\n })\n\n this.log(`attach: socket handler ready`)\n return this\n }\n\n private resetIdleTimer(): void {\n if (this.idleTimeout <= 0) return\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n }\n\n this.idleTimer = setTimeout(() => {\n const idleTime = Date.now() - this.lastActivityTime\n this.log(`idle timeout after ${idleTime}ms`)\n this.handleError(new Error('Idle timeout'))\n }, this.idleTimeout)\n }\n\n public async detach(close?: boolean): Promise<PGLiteSocketHandler> {\n this.log(`detach: detaching socket, close=${close ?? this.closeOnDetach}`)\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n this.idleTimer = undefined\n }\n\n // Clear any pending queries for this handler\n this.queryQueue.clearQueueForHandler(this.id)\n\n await this.queryQueue.clearTransactionIfNeeded(this.id)\n\n if (!this.socket) {\n this.log(`detach: no socket attached, nothing to do`)\n return this\n }\n\n // Remove all listeners\n this.socket.removeAllListeners('data')\n this.socket.removeAllListeners('error')\n this.socket.removeAllListeners('close')\n\n // Close the socket if requested\n if (close ?? this.closeOnDetach) {\n if (this.socket.writable) {\n this.log(`detach: closing socket`)\n try {\n this.socket.end()\n this.socket.destroy()\n } catch (err) {\n this.log(`detach: error closing socket:`, err)\n }\n }\n }\n\n this.socket = null\n this.active = false\n this.messageBuffer = Buffer.alloc(0)\n\n this.log(`detach: handler cleaned up`)\n return this\n }\n\n public get isAttached(): boolean {\n return this.socket !== null\n }\n\n private async handleData(data: Buffer): Promise<number> {\n if (!this.socket || !this.active) {\n this.log(`handleData: no active socket, ignoring data`)\n return 0\n }\n\n this.log(`handleData: received ${data.length} bytes`)\n\n // Append to buffer for message reassembly\n this.messageBuffer = Buffer.concat([this.messageBuffer, data])\n\n // Print the incoming data to the console\n this.inspectData('incoming', data)\n\n try {\n let totalProcessed = 0\n\n while (this.messageBuffer.length > 0) {\n // Determine message length\n let messageLength = 0\n let isComplete = false\n\n // Handle startup message (no type byte, just length)\n if (this.messageBuffer.length >= 4) {\n const firstInt = this.messageBuffer.readInt32BE(0)\n\n if (this.messageBuffer.length >= 8) {\n const secondInt = this.messageBuffer.readInt32BE(4)\n // PostgreSQL 3.0 protocol version\n if (secondInt === 196608 || secondInt === 0x00030000) {\n messageLength = firstInt\n isComplete = this.messageBuffer.length >= messageLength\n }\n }\n\n // Regular message (type byte + length)\n if (!isComplete && this.messageBuffer.length >= 5) {\n const msgLength = this.messageBuffer.readInt32BE(1)\n messageLength = 1 + msgLength\n isComplete = this.messageBuffer.length >= messageLength\n }\n }\n\n if (!isComplete || messageLength === 0) {\n this.log(\n `handleData: incomplete message, buffering ${this.messageBuffer.length} bytes`,\n )\n break\n }\n\n // Extract and process complete message\n const message = this.messageBuffer.slice(0, messageLength)\n this.messageBuffer = this.messageBuffer.slice(messageLength)\n\n this.log(`handleData: processing message of ${message.length} bytes`)\n\n // Check if socket is still active before processing\n if (!this.active || !this.socket) {\n this.log(`handleData: socket no longer active, stopping processing`)\n break\n }\n\n // Queue the query for execution\n // This allows multiple connections to queue queries simultaneously\n const result = await this.queryQueue.enqueue(\n this.id,\n new Uint8Array(message),\n )\n\n this.log(`handleData: received ${result.length} bytes from PGlite`)\n\n // Print the outgoing data to the console\n this.inspectData('outgoing', result)\n\n // Send response if available\n if (\n result.length > 0 &&\n this.socket &&\n this.socket.writable &&\n this.active\n ) {\n await new Promise<number>((resolve, reject) => {\n this.log(`handleData: writing response to socket`)\n if (this.socket?.writable) {\n this.socket.write(Buffer.from(result), (err?: any) => {\n if (err) {\n this.log(`handleData: error writing to socket:`, err)\n reject(err)\n } else {\n this.log(`handleData: socket sent: ${result.length} bytes`)\n resolve(result.length)\n }\n })\n } else {\n this.log(`handleData: socket no longer writable`)\n resolve(0)\n }\n }).catch((writeErr) => {\n this.log(`handleData: failed to write to socket:`, writeErr)\n throw writeErr\n })\n }\n\n totalProcessed += result.length\n }\n\n // Emit data event with byte sizes\n this.dispatchEvent(\n new CustomEvent('data', {\n detail: { incoming: data.length, outgoing: totalProcessed },\n }),\n )\n\n return totalProcessed\n } catch (err) {\n this.log(`handleData: error processing data:`, err)\n throw err\n }\n }\n\n private handleError(err: Error): void {\n if (!this.active) {\n this.log(`handleError: handler not active, ignoring error`)\n return\n }\n\n // ECONNRESET is expected behavior when clients disconnect\n if (err.message?.includes('ECONNRESET')) {\n this.log(\n `handleError: client disconnected (ECONNRESET) - normal behavior`,\n )\n } else if (err.message?.includes('Idle timeout')) {\n this.log(`handleError: connection idle timeout`)\n } else {\n this.log(`handleError:`, err)\n }\n\n this.active = false\n\n // Emit error event\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n\n // Clean up\n this.detach(true)\n }\n\n private handleClose(): void {\n this.log(`handleClose: socket closed`)\n this.active = false\n this.dispatchEvent(new CustomEvent('close'))\n this.detach(false)\n }\n\n private inspectData(\n direction: 'incoming' | 'outgoing',\n data: Buffer | Uint8Array,\n ): void {\n if (!this.inspect) return\n console.log('-'.repeat(75))\n if (direction === 'incoming') {\n console.log('-> incoming', data.length, 'bytes')\n } else {\n console.log('<- outgoing', data.length, 'bytes')\n }\n\n for (let offset = 0; offset < data.length; offset += 16) {\n const chunkSize = Math.min(16, data.length - offset)\n\n let hexPart = ''\n for (let i = 0; i < 16; i++) {\n if (i < chunkSize) {\n const byte = data[offset + i]\n hexPart += byte.toString(16).padStart(2, '0') + ' '\n } else {\n hexPart += ' '\n }\n }\n\n let asciiPart = ''\n for (let i = 0; i < chunkSize; i++) {\n const byte = data[offset + i]\n asciiPart += byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : '.'\n }\n\n console.log(\n `${offset.toString(16).padStart(8, '0')} ${hexPart} ${asciiPart}`,\n )\n }\n }\n}\n\n/**\n * Options for creating a PGLiteSocketServer\n */\nexport interface PGLiteSocketServerOptions {\n /** The PGlite database instance */\n db: PGlite\n /** The port to listen on (default: 5432) */\n port?: number\n /** The host to bind to (default: 127.0.0.1) */\n host?: string\n /** Unix socket path to bind to (default: undefined) */\n path?: string\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n /** Idle timeout in ms (0 to disable, default: 0) */\n idleTimeout?: number\n /** Maximum concurrent connections (default: 100) */\n maxConnections?: number\n}\n\n/**\n * PGLite Socket Server with support for multiple concurrent connections\n * Connections remain open and queries are queued at the query level\n */\nexport class PGLiteSocketServer extends EventTarget {\n readonly db: PGlite\n private server: Server | null = null\n private port?: number\n private host?: string\n private path?: string\n private active = false\n private inspect: boolean\n private debug: boolean\n private idleTimeout: number\n private maxConnections: number\n private handlers: Set<PGLiteSocketHandler> = new Set()\n private queryQueue: QueryQueueManager\n\n constructor(options: PGLiteSocketServerOptions) {\n super()\n this.db = options.db\n if (options.path) {\n this.path = options.path\n } else {\n if (typeof options.port === 'number') {\n // Keep port undefined on port 0, will be set by the OS when we start the server.\n this.port = options.port ?? options.port\n } else {\n this.port = 5432\n }\n this.host = options.host || '127.0.0.1'\n }\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.idleTimeout = options.idleTimeout ?? 0\n this.maxConnections = options.maxConnections ?? 1\n\n // Create the shared query queue\n this.queryQueue = new QueryQueueManager(this.db, this.debug)\n\n this.log(`constructor: created server on ${this.getServerConn()}`)\n this.log(`constructor: max connections: ${this.maxConnections}`)\n if (this.idleTimeout > 0) {\n this.log(`constructor: idle timeout: ${this.idleTimeout}ms`)\n }\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketServer] ${message}`, ...args)\n }\n }\n\n public async start(): Promise<void> {\n this.log(`start: starting server on ${this.getServerConn()}`)\n\n if (this.server) {\n throw new Error('Socket server already started')\n }\n\n // Ensure PGlite is ready before accepting connections\n await this.db.waitReady\n\n this.active = true\n this.server = createServer((socket) => {\n setImmediate(() => this.handleConnection(socket))\n })\n\n this.server.maxConnections = this.maxConnections\n\n return new Promise<void>((resolve, reject) => {\n if (!this.server) return reject(new Error('Server not initialized'))\n\n this.server.on('error', (err) => {\n this.log(`start: server error:`, err)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n if (!this.active) {\n reject(err)\n }\n })\n\n if (this.path) {\n this.server.listen(this.path, () => {\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { path: this.path },\n }),\n )\n resolve()\n })\n } else {\n const server = this.server\n server.listen(this.port, this.host, () => {\n const address = server.address()\n // We are not using pipes, so return type should be AddressInfo\n if (address === null || typeof address !== 'object') {\n throw Error('Expected address info')\n }\n // Assign the new port number\n this.port = address.port\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { port: this.port, host: this.host },\n }),\n )\n resolve()\n })\n }\n })\n }\n\n public getServerConn(): string {\n if (this.path) return this.path\n return `${this.host}:${this.port}`\n }\n\n public async stop(): Promise<void> {\n this.log(`stop: stopping server`)\n\n this.active = false\n\n // Detach all handlers\n this.log(`stop: detaching ${this.handlers.size} handlers`)\n for (const handler of this.handlers) {\n handler.detach(true)\n }\n this.handlers.clear()\n\n if (!this.server) {\n this.log(`stop: server not running, nothing to do`)\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve) => {\n if (!this.server) return resolve()\n\n this.server.close(() => {\n this.log(`stop: server closed`)\n this.server = null\n this.dispatchEvent(new CustomEvent('close'))\n resolve()\n })\n })\n }\n\n private async handleConnection(socket: Socket): Promise<void> {\n const clientInfo = {\n clientAddress: socket.remoteAddress || 'unknown',\n clientPort: socket.remotePort || 0,\n }\n\n this.log(\n `handleConnection: new connection from ${clientInfo.clientAddress}:${clientInfo.clientPort}`,\n )\n this.log(\n `handleConnection: active connections: ${this.handlers.size}, queued queries: ${this.queryQueue.getQueueLength()}`,\n )\n\n if (!this.active) {\n this.log(`handleConnection: server not active, closing connection`)\n try {\n socket.end()\n } catch (err) {\n this.log(`handleConnection: error closing socket:`, err)\n }\n return\n }\n\n // Check connection limit\n if (this.handlers.size >= this.maxConnections) {\n this.log(`handleConnection: max connections reached, rejecting`)\n socket.write(Buffer.from('Too many connections\\n'))\n socket.end()\n return\n }\n\n // Create a new handler for this connection\n const handler = new PGLiteSocketHandler({\n queryQueue: this.queryQueue,\n closeOnDetach: true,\n inspect: this.inspect,\n debug: this.debug,\n idleTimeout: this.idleTimeout,\n })\n\n // Track this handler\n this.handlers.add(handler)\n\n // Handle errors\n handler.addEventListener('error', (event) => {\n const error = (event as CustomEvent<Error>).detail\n\n if (error?.message?.includes('ECONNRESET')) {\n this.log(\n `handler #${handler.handlerId}: client disconnected (ECONNRESET)`,\n )\n } else if (error?.message?.includes('Idle timeout')) {\n this.log(`handler #${handler.handlerId}: idle timeout`)\n } else {\n this.log(`handler #${handler.handlerId}: error:`, error)\n }\n })\n\n // Handle close event\n handler.addEventListener('close', () => {\n this.log(`handler #${handler.handlerId}: closed`)\n this.handlers.delete(handler)\n this.log(`handleConnection: active connections: ${this.handlers.size}`)\n })\n\n try {\n await handler.attach(socket)\n this.dispatchEvent(new CustomEvent('connection', { detail: clientInfo }))\n } catch (err) {\n this.log(`handleConnection: error attaching socket:`, err)\n this.handlers.delete(handler)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n try {\n socket.end()\n } catch (closeErr) {\n this.log(`handleConnection: error closing socket:`, closeErr)\n }\n }\n }\n\n public getStats() {\n return {\n activeConnections: this.handlers.size,\n queuedQueries: this.queryQueue.getQueueLength(),\n maxConnections: this.maxConnections,\n }\n }\n}\n"],"mappings":"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","names":["import_pglite","import_net","QueryQueueManager","db","debug","message","args","handlerId","resolve","reject","query","i","q","waitTime","result","error","before","removed","_PGLiteSocketHandler","options","socket","data","err","idleTime","close","totalProcessed","messageLength","isComplete","firstInt","secondInt","writeErr","direction","offset","chunkSize","hexPart","byte","asciiPart","PGLiteSocketHandler","PGLiteSocketServer","server","address","handler","clientInfo","event","closeErr","import_node_util","import_node_child_process","args","help","PGLiteServerRunner","config","extensionsArg","host","port","path","socketDir","extensions","builtInExtensions","name","ext","packagePath","exportName","error","event","detail","databaseUrl","clientAddress","clientPort","PGLiteSocketServer","SubprocessManager","exitCode","onExit","command","includeDatabaseUrl","env","commandParts","code","timeout","main"]}
{"version":3,"sources":["../../src/scripts/server.ts","../../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { PGlite, DebugLevel } from '@electric-sql/pglite'\nimport type { Extension, Extensions } from '@electric-sql/pglite'\nimport { PGLiteSocketServer } from '../index'\nimport { parseArgs } from 'node:util'\nimport { spawn, ChildProcess } from 'node:child_process'\n\n// Define command line argument options\nconst args = parseArgs({\n options: {\n db: {\n type: 'string',\n short: 'd',\n default: 'memory://',\n help: 'Database path (relative or absolute). Use memory:// for in-memory database.',\n },\n port: {\n type: 'string',\n short: 'p',\n default: '5432',\n help: 'Port to listen on',\n },\n host: {\n type: 'string',\n short: 'h',\n default: '127.0.0.1',\n help: 'Host to bind to',\n },\n path: {\n type: 'string',\n short: 'u',\n default: undefined,\n help: 'unix socket to bind to. Takes precedence over host:port',\n },\n debug: {\n type: 'string',\n short: 'v',\n default: '0',\n help: 'Debug level (0-5)',\n },\n extensions: {\n type: 'string',\n short: 'e',\n default: undefined,\n help: 'Comma-separated list of extensions to load (e.g., vector,pgcrypto,postgis etc.)',\n },\n run: {\n type: 'string',\n short: 'r',\n default: undefined,\n help: 'Command to run after server starts',\n },\n 'include-database-url': {\n type: 'boolean',\n default: false,\n help: 'Include DATABASE_URL in the environment of the subprocess',\n },\n 'shutdown-timeout': {\n type: 'string',\n default: '5000',\n help: 'Timeout in milliseconds for graceful subprocess shutdown (default: 5000)',\n },\n 'max-connections': {\n type: 'string',\n short: 'm',\n default: '1',\n help: 'Maximum concurrent connections (default: 1)',\n },\n help: {\n type: 'boolean',\n short: '?',\n default: false,\n help: 'Show help',\n },\n },\n})\n\nconst help = `PGlite Socket Server\nUsage: pglite-server [options]\n\nOptions:\n -d, --db=PATH Database path (default: memory://)\n -p, --port=PORT Port to listen on (default: 5432)\n -h, --host=HOST Host to bind to (default: 127.0.0.1)\n -u, --path=UNIX Unix socket to bind to (default: undefined). Takes precedence over host:port\n -v, --debug=LEVEL Debug level 0-5 (default: 0)\n -e, --extensions=LIST Comma-separated list of extensions to load\n Formats: vector, pgcrypto (built-in/contrib)\n @org/package/path:exportedName (npm package)\n -r, --run=COMMAND Command to run after server starts\n --include-database-url Include DATABASE_URL in subprocess environment\n --shutdown-timeout=MS Timeout for graceful subprocess shutdown in ms (default: 5000)\n -m, --max-connections=N Maximum concurrent connections (default is no concurrency: 1)\n`\n\ninterface ServerConfig {\n dbPath: string\n port: number\n host: string\n path?: string\n debugLevel: DebugLevel\n extensionNames?: string[]\n runCommand?: string\n includeDatabaseUrl: boolean\n shutdownTimeout: number\n maxConnections: number\n}\n\nclass PGLiteServerRunner {\n private config: ServerConfig\n private db: PGlite | null = null\n private server: PGLiteSocketServer | null = null\n private subprocessManager: SubprocessManager | null = null\n\n constructor(config: ServerConfig) {\n this.config = config\n }\n\n static parseConfig(): ServerConfig {\n const extensionsArg = args.values.extensions as string | undefined\n return {\n dbPath: args.values.db as string,\n port: parseInt(args.values.port as string, 10),\n host: args.values.host as string,\n path: args.values.path as string,\n debugLevel: parseInt(args.values.debug as string, 10) as DebugLevel,\n extensionNames: extensionsArg\n ? extensionsArg.split(',').map((e) => e.trim())\n : undefined,\n runCommand: args.values.run as string,\n includeDatabaseUrl: args.values['include-database-url'] as boolean,\n shutdownTimeout: parseInt(args.values['shutdown-timeout'] as string, 10),\n maxConnections: parseInt(args.values['max-connections'] as string, 10),\n }\n }\n\n private createDatabaseUrl(): string {\n const { host, port, path } = this.config\n\n if (path) {\n // Unix socket connection\n const socketDir = path.endsWith('/.s.PGSQL.5432')\n ? path.slice(0, -13)\n : path\n return `postgresql://postgres:postgres@/postgres?host=${encodeURIComponent(socketDir)}`\n } else {\n // TCP connection\n return `postgresql://postgres:postgres@${host}:${port}/postgres`\n }\n }\n\n private async importExtensions(): Promise<Extensions | undefined> {\n if (!this.config.extensionNames?.length) {\n return undefined\n }\n\n const extensions: Extensions = {}\n\n // Built-in extensions that are not in contrib\n const builtInExtensions = [\n 'vector',\n 'live',\n 'pg_hashids',\n 'pg_ivm',\n 'pg_uuidv7',\n 'pgtap',\n 'age',\n 'pg_textsearch',\n ]\n\n for (const name of this.config.extensionNames) {\n let ext: Extension | null = null\n\n try {\n // Check if this is a custom package path (contains ':')\n // Format: @org/package/path:exportedName or package/path:exportedName\n if (name.includes(':')) {\n const [packagePath, exportName] = name.split(':')\n if (!packagePath || !exportName) {\n throw new Error(\n `Invalid extension format '${name}'. Expected: package/path:exportedName`,\n )\n }\n const mod = await import(packagePath)\n ext = mod[exportName] as Extension\n if (ext) {\n extensions[exportName] = ext\n console.log(\n `Imported extension '${exportName}' from '${packagePath}'`,\n )\n }\n } else if (builtInExtensions.includes(name)) {\n // Built-in extension (e.g., @electric-sql/pglite/vector)\n const mod = await import(`@electric-sql/pglite/${name}`)\n ext = mod[name] as Extension\n if (ext) {\n extensions[name] = ext\n console.log(`Imported extension: ${name}`)\n }\n } else {\n // Try contrib first (e.g., @electric-sql/pglite/contrib/pgcrypto)\n try {\n const mod = await import(`@electric-sql/pglite/contrib/${name}`)\n ext = mod[name] as Extension\n } catch {\n // Fall back to external package (e.g., @electric-sql/pglite-<extension>)\n const mod = await import(`@electric-sql/pglite-${name}`)\n ext = mod[name] as Extension\n }\n if (ext) {\n extensions[name] = ext\n console.log(`Imported extension: ${name}`)\n }\n }\n } catch (error) {\n console.error(`Failed to import extension '${name}':`, error)\n throw new Error(`Failed to import extension '${name}'`)\n }\n }\n\n return Object.keys(extensions).length > 0 ? extensions : undefined\n }\n\n private async initializeDatabase(): Promise<void> {\n console.log(`Initializing PGLite with database: ${this.config.dbPath}`)\n console.log(`Debug level: ${this.config.debugLevel}`)\n\n const extensions = await this.importExtensions()\n\n this.db = new PGlite(this.config.dbPath, {\n debug: this.config.debugLevel,\n extensions,\n })\n await this.db.waitReady\n console.log('PGlite database initialized')\n }\n\n private setupServerEventHandlers(): void {\n if (!this.server || !this.subprocessManager) {\n throw new Error('Server or subprocess manager not initialized')\n }\n\n this.server.addEventListener('listening', (event) => {\n const detail = (\n event as CustomEvent<{ port: number; host: string } | { host: string }>\n ).detail\n console.log(`PGLiteSocketServer listening on ${JSON.stringify(detail)}`)\n\n // Run the command after server starts listening\n if (this.config.runCommand && this.subprocessManager) {\n const databaseUrl = this.createDatabaseUrl()\n this.subprocessManager.spawn(\n this.config.runCommand,\n databaseUrl,\n this.config.includeDatabaseUrl,\n )\n }\n })\n\n this.server.addEventListener('connection', (event) => {\n const { clientAddress, clientPort } = (\n event as CustomEvent<{ clientAddress: string; clientPort: number }>\n ).detail\n console.log(`Client connected from ${clientAddress}:${clientPort}`)\n })\n\n this.server.addEventListener('error', (event) => {\n const error = (event as CustomEvent<Error>).detail\n console.error('Socket server error:', error)\n })\n }\n\n private setupSignalHandlers(): void {\n process.on('SIGINT', () => this.shutdown())\n process.on('SIGTERM', () => this.shutdown())\n }\n\n async start(): Promise<void> {\n try {\n // Initialize database\n await this.initializeDatabase()\n\n if (!this.db) {\n throw new Error('Database initialization failed')\n }\n\n // Create and setup the socket server\n this.server = new PGLiteSocketServer({\n db: this.db,\n port: this.config.port,\n host: this.config.host,\n path: this.config.path,\n inspect: this.config.debugLevel > 0,\n maxConnections: this.config.maxConnections,\n })\n\n // Create subprocess manager\n this.subprocessManager = new SubprocessManager((exitCode) => {\n this.shutdown(exitCode)\n })\n\n // Setup event handlers\n this.setupServerEventHandlers()\n this.setupSignalHandlers()\n\n // Start the server\n await this.server.start()\n } catch (error) {\n console.error('Failed to start PGLiteSocketServer:', error)\n throw error\n }\n }\n\n async shutdown(exitCode: number = 0): Promise<void> {\n console.log('\\nShutting down PGLiteSocketServer...')\n\n // Terminate subprocess if running\n if (this.subprocessManager) {\n this.subprocessManager.terminate(this.config.shutdownTimeout)\n }\n\n // Stop server\n if (this.server) {\n await this.server.stop()\n }\n\n // Close database\n if (this.db) {\n await this.db.close()\n }\n\n console.log('Server stopped')\n process.exit(exitCode)\n }\n}\n\nclass SubprocessManager {\n private childProcess: ChildProcess | null = null\n private onExit: (code: number) => void\n\n constructor(onExit: (code: number) => void) {\n this.onExit = onExit\n }\n\n get process(): ChildProcess | null {\n return this.childProcess\n }\n\n spawn(\n command: string,\n databaseUrl: string,\n includeDatabaseUrl: boolean,\n ): void {\n console.log(`Running command: ${command}`)\n\n // Prepare environment variables\n const env = { ...process.env }\n if (includeDatabaseUrl) {\n env.DATABASE_URL = databaseUrl\n console.log(`Setting DATABASE_URL=${databaseUrl}`)\n }\n\n // Parse and spawn the command\n const commandParts = command.trim().split(/\\s+/)\n this.childProcess = spawn(commandParts[0], commandParts.slice(1), {\n env,\n stdio: 'inherit',\n })\n\n this.childProcess.on('error', (error) => {\n console.error('Error running command:', error)\n // If subprocess fails to start, shutdown the server\n console.log('Subprocess failed to start, shutting down...')\n this.onExit(1)\n })\n\n this.childProcess.on('close', (code) => {\n console.log(`Command exited with code ${code}`)\n this.childProcess = null\n\n // If child process exits with non-zero code, notify parent\n if (code !== null && code !== 0) {\n console.log(\n `Child process failed with exit code ${code}, shutting down...`,\n )\n this.onExit(code)\n }\n })\n }\n\n terminate(timeout: number): void {\n if (this.childProcess) {\n console.log('Terminating child process...')\n this.childProcess.kill('SIGTERM')\n\n // Give it a moment to exit gracefully, then force kill if needed\n setTimeout(() => {\n if (this.childProcess && !this.childProcess.killed) {\n console.log('Force killing child process...')\n this.childProcess.kill('SIGKILL')\n }\n }, timeout)\n }\n }\n}\n\n// Main execution\nasync function main() {\n // Show help and exit if requested\n if (args.values.help) {\n console.log(help)\n process.exit(0)\n }\n\n try {\n const config = PGLiteServerRunner.parseConfig()\n const serverRunner = new PGLiteServerRunner(config)\n await serverRunner.start()\n } catch (error) {\n console.error('Unhandled error:', error)\n process.exit(1)\n }\n}\n\n// Run the main function\nmain()\n","import type { PGlite } from '@electric-sql/pglite'\nimport { type Server, type Socket, createServer } from 'net'\n\n// Connection queue timeout in milliseconds\nexport const CONNECTION_QUEUE_TIMEOUT = 60000 // 60 seconds\n\n/**\n * Represents a queued query waiting for PGlite access\n */\ninterface QueuedQuery {\n handlerId: number\n message: Uint8Array\n resolve: (resultSize: number) => void\n reject: (error: Error) => void\n timestamp: number\n onData: (data: Uint8Array) => void\n}\n\n/**\n * Global query queue manager\n * Ensures only one query executes at a time in PGlite\n */\nclass QueryQueueManager {\n private queue: QueuedQuery[] = []\n private processing = false\n private db: PGlite\n private debug: boolean\n private lastHandlerId: null | number = null\n\n constructor(db: PGlite, debug = false) {\n this.db = db\n this.debug = debug\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[QueryQueueManager] ${message}`, ...args)\n }\n }\n\n async enqueue(\n handlerId: number,\n message: Uint8Array,\n onData: (data: Uint8Array) => void,\n ): Promise<number> {\n return new Promise((resolve, reject) => {\n const query: QueuedQuery = {\n handlerId,\n message,\n resolve,\n reject,\n timestamp: Date.now(),\n onData,\n }\n\n this.queue.push(query)\n this.log(\n `enqueued query from handler #${handlerId}, queue size: ${this.queue.length}`,\n )\n\n // Process queue if not already processing\n if (!this.processing) {\n this.processQueue()\n }\n })\n }\n\n private async processQueue(): Promise<void> {\n if (this.processing || this.queue.length === 0) {\n return\n }\n\n this.processing = true\n\n while (this.queue.length > 0) {\n let query\n\n if (this.db.isInTransaction() && this.lastHandlerId) {\n const i = this.queue.findIndex(\n (q) => q.handlerId === this.lastHandlerId,\n )\n if (i === -1) {\n // we didn't find any other query from the same client!\n this.log(\n `transaction started, but no query from the same handler id found in queue`,\n this.lastHandlerId,\n )\n query = null\n } else {\n query = this.queue.splice(i, 1)[0]\n }\n } else {\n query = this.queue.shift()\n }\n if (!query) break\n\n const waitTime = Date.now() - query.timestamp\n this.log(\n `processing query from handler #${query.handlerId} (waited ${waitTime}ms)`,\n )\n\n let result = 0\n try {\n // Execute the query with exclusive access to PGlite\n await this.db.runExclusive(async () => {\n return await this.db.execProtocolRawStream(query.message, {\n onRawData: (data) => {\n result += data.length\n query.onData(data)\n },\n })\n })\n } catch (error) {\n this.log(`query from handler #${query.handlerId} failed:`, error)\n query.reject(error as Error)\n return\n }\n\n this.log(\n `query from handler #${query.handlerId} completed, ${result} bytes`,\n )\n this.lastHandlerId = query.handlerId\n query.resolve(result)\n }\n\n this.processing = false\n this.log(`queue processing complete, queue length is`, this.queue.length)\n }\n\n getQueueLength(): number {\n return this.queue.length\n }\n\n clearQueueForHandler(handlerId: number): void {\n const before = this.queue.length\n this.queue = this.queue.filter((q) => {\n if (q.handlerId === handlerId) {\n q.reject(new Error('Handler disconnected'))\n return false\n }\n return true\n })\n const removed = before - this.queue.length\n if (removed > 0) {\n this.log(`cleared ${removed} queries for handler #${handlerId}`)\n }\n }\n\n async clearTransactionIfNeeded(handlerId: number): Promise<void> {\n if (this.db.isInTransaction() && this.lastHandlerId === handlerId) {\n await this.db.exec('ROLLBACK')\n this.lastHandlerId = null\n await this.processQueue()\n }\n }\n}\n\n/**\n * Options for creating a PGLiteSocketHandler\n */\nexport interface PGLiteSocketHandlerOptions {\n /** The query queue manager */\n queryQueue: QueryQueueManager\n /** Whether to close the socket when detached (default: false) */\n closeOnDetach?: boolean\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n /** Idle timeout in ms (0 to disable, default: 0) */\n idleTimeout?: number\n}\n\n/**\n * Handler for a single socket connection to PGlite\n * Each connection can remain open and send multiple queries\n */\nexport class PGLiteSocketHandler extends EventTarget {\n private queryQueue: QueryQueueManager\n private socket: Socket | null = null\n private active = false\n private closeOnDetach: boolean\n private inspect: boolean\n private debug: boolean\n private readonly id: number\n private messageBuffer: Buffer = Buffer.alloc(0)\n private idleTimer?: NodeJS.Timeout\n private idleTimeout: number\n private lastActivityTime: number = Date.now()\n\n // Static counter for generating unique handler IDs\n private static nextHandlerId = 1\n\n constructor(options: PGLiteSocketHandlerOptions) {\n super()\n this.queryQueue = options.queryQueue\n this.closeOnDetach = options.closeOnDetach ?? false\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.idleTimeout = options.idleTimeout ?? 0\n this.id = PGLiteSocketHandler.nextHandlerId++\n\n this.log('constructor: created new handler')\n }\n\n public get handlerId(): number {\n return this.id\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketHandler#${this.id}] ${message}`, ...args)\n }\n }\n\n public async attach(socket: Socket): Promise<PGLiteSocketHandler> {\n this.log(\n `attach: attaching socket from ${socket.remoteAddress}:${socket.remotePort}`,\n )\n\n if (this.socket) {\n throw new Error('Socket already attached')\n }\n\n this.socket = socket\n this.active = true\n this.lastActivityTime = Date.now()\n\n // Set up socket options\n socket.setNoDelay(true)\n\n // Set up idle timeout if configured\n if (this.idleTimeout > 0) {\n this.resetIdleTimer()\n }\n\n // Setup event handlers\n this.log(`attach: setting up socket event handlers`)\n\n socket.on('data', (data) => {\n this.lastActivityTime = Date.now()\n this.resetIdleTimer()\n\n setImmediate(async () => {\n try {\n await this.handleData(data)\n } catch (err) {\n this.log('socket on data error: ', err)\n this.handleError(err as Error)\n }\n })\n })\n\n socket.on('error', (err) => {\n setImmediate(() => this.handleError(err))\n })\n\n socket.on('close', () => {\n setImmediate(() => this.handleClose())\n })\n\n this.log(`attach: socket handler ready`)\n return this\n }\n\n private resetIdleTimer(): void {\n if (this.idleTimeout <= 0) return\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n }\n\n this.idleTimer = setTimeout(() => {\n const idleTime = Date.now() - this.lastActivityTime\n this.log(`idle timeout after ${idleTime}ms`)\n this.handleError(new Error('Idle timeout'))\n }, this.idleTimeout)\n }\n\n public async detach(close?: boolean): Promise<PGLiteSocketHandler> {\n this.log(`detach: detaching socket, close=${close ?? this.closeOnDetach}`)\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n this.idleTimer = undefined\n }\n\n // Clear any pending queries for this handler\n this.queryQueue.clearQueueForHandler(this.id)\n\n await this.queryQueue.clearTransactionIfNeeded(this.id)\n\n if (!this.socket) {\n this.log(`detach: no socket attached, nothing to do`)\n return this\n }\n\n // Remove all listeners\n this.socket.removeAllListeners('data')\n this.socket.removeAllListeners('error')\n this.socket.removeAllListeners('close')\n\n // Close the socket if requested\n if (close ?? this.closeOnDetach) {\n if (this.socket.writable) {\n this.log(`detach: closing socket`)\n try {\n this.socket.end()\n this.socket.destroy()\n } catch (err) {\n this.log(`detach: error closing socket:`, err)\n }\n }\n }\n\n this.socket = null\n this.active = false\n this.messageBuffer = Buffer.alloc(0)\n\n this.log(`detach: handler cleaned up`)\n return this\n }\n\n public get isAttached(): boolean {\n return this.socket !== null\n }\n\n private async handleData(data: Buffer): Promise<number> {\n if (!this.socket || !this.active) {\n this.log(`handleData: no active socket, ignoring data`)\n return 0\n }\n\n this.log(`handleData: received ${data.length} bytes`)\n\n // Append to buffer for message reassembly\n this.messageBuffer = Buffer.concat([this.messageBuffer, data])\n\n // Print the incoming data to the console\n this.inspectData('incoming', data)\n\n try {\n let totalProcessed = 0\n\n while (this.messageBuffer.length > 0) {\n // Determine message length\n let messageLength = 0\n let isComplete = false\n\n // Handle startup message (no type byte, just length)\n if (this.messageBuffer.length >= 4) {\n const firstInt = this.messageBuffer.readInt32BE(0)\n\n if (this.messageBuffer.length >= 8) {\n const secondInt = this.messageBuffer.readInt32BE(4)\n // PostgreSQL 3.0 protocol version\n if (secondInt === 196608 || secondInt === 0x00030000) {\n messageLength = firstInt\n isComplete = this.messageBuffer.length >= messageLength\n }\n }\n\n // Regular message (type byte + length)\n if (!isComplete && this.messageBuffer.length >= 5) {\n const msgLength = this.messageBuffer.readInt32BE(1)\n messageLength = 1 + msgLength\n isComplete = this.messageBuffer.length >= messageLength\n }\n }\n\n if (!isComplete || messageLength === 0) {\n this.log(\n `handleData: incomplete message, buffering ${this.messageBuffer.length} bytes`,\n )\n break\n }\n\n // Extract and process complete message\n const message = this.messageBuffer.slice(0, messageLength)\n this.messageBuffer = this.messageBuffer.slice(messageLength)\n\n this.log(`handleData: processing message of ${message.length} bytes`)\n\n // Check if socket is still active before processing\n if (!this.active || !this.socket) {\n this.log(`handleData: socket no longer active, stopping processing`)\n break\n }\n\n let socketWriteError: any = undefined\n // Queue the query for execution\n // This allows multiple connections to queue queries simultaneously\n await this.queryQueue.enqueue(\n this.id,\n new Uint8Array(message),\n (data) => {\n this.log(`handleData: received ${data.length} bytes from PGlite`)\n\n // Print the outgoing data to the console\n this.inspectData('outgoing', data)\n\n // Send response if available\n if (\n data.length > 0 &&\n this.socket &&\n this.socket.writable &&\n this.active\n ) {\n // await new Promise<number>((resolve, reject) => {\n this.log(`handleData: writing response to socket`)\n if (this.socket?.writable) {\n this.socket.write(Buffer.from(data), (err?: any) => {\n if (err) {\n this.log(`handleData: error writing to socket:`, err)\n socketWriteError = err\n } else {\n this.log(`handleData: socket sent: ${data.length} bytes`)\n }\n })\n } else {\n this.log(`handleData: socket no longer writable`)\n }\n }\n totalProcessed += data.length\n },\n )\n if (socketWriteError) throw socketWriteError\n }\n\n // Emit data event with byte sizes\n this.dispatchEvent(\n new CustomEvent('data', {\n detail: { incoming: data.length, outgoing: totalProcessed },\n }),\n )\n\n return totalProcessed\n } catch (err) {\n this.log(`handleData: error processing data:`, err)\n throw err\n }\n }\n\n private handleError(err: Error): void {\n if (!this.active) {\n this.log(`handleError: handler not active, ignoring error`)\n return\n }\n\n // ECONNRESET is expected behavior when clients disconnect\n if (err.message?.includes('ECONNRESET')) {\n this.log(\n `handleError: client disconnected (ECONNRESET) - normal behavior`,\n )\n } else if (err.message?.includes('Idle timeout')) {\n this.log(`handleError: connection idle timeout`)\n } else {\n this.log(`handleError:`, err)\n }\n\n this.active = false\n\n // Emit error event\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n\n // Clean up\n this.detach(true)\n }\n\n private handleClose(): void {\n this.log(`handleClose: socket closed`)\n this.active = false\n this.dispatchEvent(new CustomEvent('close'))\n this.detach(false)\n }\n\n private inspectData(\n direction: 'incoming' | 'outgoing',\n data: Buffer | Uint8Array,\n ): void {\n if (!this.inspect) return\n console.log('-'.repeat(75))\n if (direction === 'incoming') {\n console.log('-> incoming', data.length, 'bytes')\n } else {\n console.log('<- outgoing', data.length, 'bytes')\n }\n\n for (let offset = 0; offset < data.length; offset += 16) {\n const chunkSize = Math.min(16, data.length - offset)\n\n let hexPart = ''\n for (let i = 0; i < 16; i++) {\n if (i < chunkSize) {\n const byte = data[offset + i]\n hexPart += byte.toString(16).padStart(2, '0') + ' '\n } else {\n hexPart += ' '\n }\n }\n\n let asciiPart = ''\n for (let i = 0; i < chunkSize; i++) {\n const byte = data[offset + i]\n asciiPart += byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : '.'\n }\n\n console.log(\n `${offset.toString(16).padStart(8, '0')} ${hexPart} ${asciiPart}`,\n )\n }\n }\n}\n\n/**\n * Options for creating a PGLiteSocketServer\n */\nexport interface PGLiteSocketServerOptions {\n /** The PGlite database instance */\n db: PGlite\n /** The port to listen on (default: 5432) */\n port?: number\n /** The host to bind to (default: 127.0.0.1) */\n host?: string\n /** Unix socket path to bind to (default: undefined) */\n path?: string\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n /** Idle timeout in ms (0 to disable, default: 0) */\n idleTimeout?: number\n /** Maximum concurrent connections (default: 100) */\n maxConnections?: number\n}\n\n/**\n * PGLite Socket Server with support for multiple concurrent connections\n * Connections remain open and queries are queued at the query level\n */\nexport class PGLiteSocketServer extends EventTarget {\n readonly db: PGlite\n private server: Server | null = null\n private port?: number\n private host?: string\n private path?: string\n private active = false\n private inspect: boolean\n private debug: boolean\n private idleTimeout: number\n private maxConnections: number\n private handlers: Set<PGLiteSocketHandler> = new Set()\n private queryQueue: QueryQueueManager\n\n constructor(options: PGLiteSocketServerOptions) {\n super()\n this.db = options.db\n if (options.path) {\n this.path = options.path\n } else {\n if (typeof options.port === 'number') {\n // Keep port undefined on port 0, will be set by the OS when we start the server.\n this.port = options.port ?? options.port\n } else {\n this.port = 5432\n }\n this.host = options.host || '127.0.0.1'\n }\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.idleTimeout = options.idleTimeout ?? 0\n this.maxConnections = options.maxConnections ?? 1\n\n // Create the shared query queue\n this.queryQueue = new QueryQueueManager(this.db, this.debug)\n\n this.log(`constructor: created server on ${this.getServerConn()}`)\n this.log(`constructor: max connections: ${this.maxConnections}`)\n if (this.idleTimeout > 0) {\n this.log(`constructor: idle timeout: ${this.idleTimeout}ms`)\n }\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketServer] ${message}`, ...args)\n }\n }\n\n public async start(): Promise<void> {\n this.log(`start: starting server on ${this.getServerConn()}`)\n\n if (this.server) {\n throw new Error('Socket server already started')\n }\n\n // Ensure PGlite is ready before accepting connections\n await this.db.waitReady\n\n this.active = true\n this.server = createServer((socket) => {\n setImmediate(() => this.handleConnection(socket))\n })\n\n this.server.maxConnections = this.maxConnections\n\n return new Promise<void>((resolve, reject) => {\n if (!this.server) return reject(new Error('Server not initialized'))\n\n this.server.on('error', (err) => {\n this.log(`start: server error:`, err)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n if (!this.active) {\n reject(err)\n }\n })\n\n if (this.path) {\n this.server.listen(this.path, () => {\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { path: this.path },\n }),\n )\n resolve()\n })\n } else {\n const server = this.server\n server.listen(this.port, this.host, () => {\n const address = server.address()\n // We are not using pipes, so return type should be AddressInfo\n if (address === null || typeof address !== 'object') {\n throw Error('Expected address info')\n }\n // Assign the new port number\n this.port = address.port\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { port: this.port, host: this.host },\n }),\n )\n resolve()\n })\n }\n })\n }\n\n public getServerConn(): string {\n if (this.path) return this.path\n return `${this.host}:${this.port}`\n }\n\n public async stop(): Promise<void> {\n this.log(`stop: stopping server`)\n\n this.active = false\n\n // Detach all handlers\n this.log(`stop: detaching ${this.handlers.size} handlers`)\n for (const handler of this.handlers) {\n handler.detach(true)\n }\n this.handlers.clear()\n\n if (!this.server) {\n this.log(`stop: server not running, nothing to do`)\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve) => {\n if (!this.server) return resolve()\n\n this.server.close(() => {\n this.log(`stop: server closed`)\n this.server = null\n this.dispatchEvent(new CustomEvent('close'))\n resolve()\n })\n })\n }\n\n private async handleConnection(socket: Socket): Promise<void> {\n const clientInfo = {\n clientAddress: socket.remoteAddress || 'unknown',\n clientPort: socket.remotePort || 0,\n }\n\n this.log(\n `handleConnection: new connection from ${clientInfo.clientAddress}:${clientInfo.clientPort}`,\n )\n this.log(\n `handleConnection: active connections: ${this.handlers.size}, queued queries: ${this.queryQueue.getQueueLength()}`,\n )\n\n if (!this.active) {\n this.log(`handleConnection: server not active, closing connection`)\n try {\n socket.end()\n } catch (err) {\n this.log(`handleConnection: error closing socket:`, err)\n }\n return\n }\n\n // Check connection limit\n if (this.handlers.size >= this.maxConnections) {\n this.log(`handleConnection: max connections reached, rejecting`)\n socket.write(Buffer.from('Too many connections\\n'))\n socket.end()\n return\n }\n\n // Create a new handler for this connection\n const handler = new PGLiteSocketHandler({\n queryQueue: this.queryQueue,\n closeOnDetach: true,\n inspect: this.inspect,\n debug: this.debug,\n idleTimeout: this.idleTimeout,\n })\n\n // Track this handler\n this.handlers.add(handler)\n\n // Handle errors\n handler.addEventListener('error', (event) => {\n const error = (event as CustomEvent<Error>).detail\n\n if (error?.message?.includes('ECONNRESET')) {\n this.log(\n `handler #${handler.handlerId}: client disconnected (ECONNRESET)`,\n )\n } else if (error?.message?.includes('Idle timeout')) {\n this.log(`handler #${handler.handlerId}: idle timeout`)\n } else {\n this.log(`handler #${handler.handlerId}: error:`, error)\n }\n })\n\n // Handle close event\n handler.addEventListener('close', () => {\n this.log(`handler #${handler.handlerId}: closed`)\n this.handlers.delete(handler)\n this.log(`handleConnection: active connections: ${this.handlers.size}`)\n })\n\n try {\n await handler.attach(socket)\n this.dispatchEvent(new CustomEvent('connection', { detail: clientInfo }))\n } catch (err) {\n this.log(`handleConnection: error attaching socket:`, err)\n this.handlers.delete(handler)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n try {\n socket.end()\n } catch (closeErr) {\n this.log(`handleConnection: error closing socket:`, closeErr)\n }\n }\n }\n\n public getStats() {\n return {\n activeConnections: this.handlers.size,\n queuedQueries: this.queryQueue.getQueueLength(),\n maxConnections: this.maxConnections,\n }\n }\n}\n"],"mappings":"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","names":["import_pglite","import_net","QueryQueueManager","db","debug","message","args","handlerId","onData","resolve","reject","query","i","q","waitTime","result","data","error","before","removed","_PGLiteSocketHandler","options","socket","err","idleTime","close","totalProcessed","messageLength","isComplete","firstInt","secondInt","socketWriteError","direction","offset","chunkSize","hexPart","byte","asciiPart","PGLiteSocketHandler","PGLiteSocketServer","server","address","handler","clientInfo","event","closeErr","import_node_util","import_node_child_process","args","help","PGLiteServerRunner","config","extensionsArg","host","port","path","socketDir","extensions","builtInExtensions","name","ext","packagePath","exportName","error","event","detail","databaseUrl","clientAddress","clientPort","PGLiteSocketServer","SubprocessManager","exitCode","onExit","command","includeDatabaseUrl","env","commandParts","code","timeout","main"]}
#!/usr/bin/env node
import{c as d}from"../chunk-JGAU6COP.js";import{PGlite as u}from"@electric-sql/pglite";import{parseArgs as h}from"node:util";import{spawn as p}from"node:child_process";var r=h({options:{db:{type:"string",short:"d",default:"memory://",help:"Database path (relative or absolute). Use memory:// for in-memory database."},port:{type:"string",short:"p",default:"5432",help:"Port to listen on"},host:{type:"string",short:"h",default:"127.0.0.1",help:"Host to bind to"},path:{type:"string",short:"u",default:void 0,help:"unix socket to bind to. Takes precedence over host:port"},debug:{type:"string",short:"v",default:"0",help:"Debug level (0-5)"},extensions:{type:"string",short:"e",default:void 0,help:"Comma-separated list of extensions to load (e.g., vector,pgcrypto)"},run:{type:"string",short:"r",default:void 0,help:"Command to run after server starts"},"include-database-url":{type:"boolean",default:!1,help:"Include DATABASE_URL in the environment of the subprocess"},"shutdown-timeout":{type:"string",default:"5000",help:"Timeout in milliseconds for graceful subprocess shutdown (default: 5000)"},"max-connections":{type:"string",short:"m",default:"1",help:"Maximum concurrent connections (default: 1)"},help:{type:"boolean",short:"?",default:!1,help:"Show help"}}}),g=`PGlite Socket Server
import{c as d}from"../chunk-NSUMFCRM.js";import{PGlite as u}from"@electric-sql/pglite";import{parseArgs as h}from"node:util";import{spawn as p}from"node:child_process";var r=h({options:{db:{type:"string",short:"d",default:"memory://",help:"Database path (relative or absolute). Use memory:// for in-memory database."},port:{type:"string",short:"p",default:"5432",help:"Port to listen on"},host:{type:"string",short:"h",default:"127.0.0.1",help:"Host to bind to"},path:{type:"string",short:"u",default:void 0,help:"unix socket to bind to. Takes precedence over host:port"},debug:{type:"string",short:"v",default:"0",help:"Debug level (0-5)"},extensions:{type:"string",short:"e",default:void 0,help:"Comma-separated list of extensions to load (e.g., vector,pgcrypto,postgis etc.)"},run:{type:"string",short:"r",default:void 0,help:"Command to run after server starts"},"include-database-url":{type:"boolean",default:!1,help:"Include DATABASE_URL in the environment of the subprocess"},"shutdown-timeout":{type:"string",default:"5000",help:"Timeout in milliseconds for graceful subprocess shutdown (default: 5000)"},"max-connections":{type:"string",short:"m",default:"1",help:"Maximum concurrent connections (default: 1)"},help:{type:"boolean",short:"?",default:!1,help:"Show help"}}}),g=`PGlite Socket Server
Usage: pglite-server [options]

@@ -18,4 +18,4 @@

-m, --max-connections=N Maximum concurrent connections (default is no concurrency: 1)
`,l=class{constructor(e){this.db=null;this.server=null;this.subprocessManager=null;this.config=e}static parseConfig(){let e=r.values.extensions;return{dbPath:r.values.db,port:parseInt(r.values.port,10),host:r.values.host,path:r.values.path,debugLevel:parseInt(r.values.debug,10),extensionNames:e?e.split(",").map(o=>o.trim()):void 0,runCommand:r.values.run,includeDatabaseUrl:r.values["include-database-url"],shutdownTimeout:parseInt(r.values["shutdown-timeout"],10),maxConnections:parseInt(r.values["max-connections"],10)}}createDatabaseUrl(){let{host:e,port:o,path:t}=this.config;if(t){let s=t.endsWith("/.s.PGSQL.5432")?t.slice(0,-13):t;return`postgresql://postgres:postgres@/postgres?host=${encodeURIComponent(s)}`}else return`postgresql://postgres:postgres@${e}:${o}/postgres`}async importExtensions(){if(!this.config.extensionNames?.length)return;let e={},o=["vector","live","pg_hashids","pg_ivm","pg_uuidv7","pgtap"];for(let t of this.config.extensionNames){let s=null;try{if(t.includes(":")){let[i,n]=t.split(":");if(!i||!n)throw new Error(`Invalid extension format '${t}'. Expected: package/path:exportedName`);s=(await import(i))[n],s&&(e[n]=s,console.log(`Imported extension '${n}' from '${i}'`))}else if(o.includes(t))s=(await import(`@electric-sql/pglite/${t}`))[t],s&&(e[t]=s,console.log(`Imported extension: ${t}`));else{try{s=(await import(`@electric-sql/pglite/contrib/${t}`))[t]}catch{s=(await import(`@electric-sql/pglite-${t}`))[t]}s&&(e[t]=s,console.log(`Imported extension: ${t}`))}}catch(i){throw console.error(`Failed to import extension '${t}':`,i),new Error(`Failed to import extension '${t}'`)}}return Object.keys(e).length>0?e:void 0}async initializeDatabase(){console.log(`Initializing PGLite with database: ${this.config.dbPath}`),console.log(`Debug level: ${this.config.debugLevel}`);let e=await this.importExtensions();this.db=new u(this.config.dbPath,{debug:this.config.debugLevel,extensions:e}),await this.db.waitReady,console.log("PGlite database initialized")}setupServerEventHandlers(){if(!this.server||!this.subprocessManager)throw new Error("Server or subprocess manager not initialized");this.server.addEventListener("listening",e=>{let o=e.detail;if(console.log(`PGLiteSocketServer listening on ${JSON.stringify(o)}`),this.config.runCommand&&this.subprocessManager){let t=this.createDatabaseUrl();this.subprocessManager.spawn(this.config.runCommand,t,this.config.includeDatabaseUrl)}}),this.server.addEventListener("connection",e=>{let{clientAddress:o,clientPort:t}=e.detail;console.log(`Client connected from ${o}:${t}`)}),this.server.addEventListener("error",e=>{let o=e.detail;console.error("Socket server error:",o)})}setupSignalHandlers(){process.on("SIGINT",()=>this.shutdown()),process.on("SIGTERM",()=>this.shutdown())}async start(){try{if(await this.initializeDatabase(),!this.db)throw new Error("Database initialization failed");this.server=new d({db:this.db,port:this.config.port,host:this.config.host,path:this.config.path,inspect:this.config.debugLevel>0,maxConnections:this.config.maxConnections}),this.subprocessManager=new c(e=>{this.shutdown(e)}),this.setupServerEventHandlers(),this.setupSignalHandlers(),await this.server.start()}catch(e){throw console.error("Failed to start PGLiteSocketServer:",e),e}}async shutdown(e=0){console.log(`
`,l=class{constructor(e){this.db=null;this.server=null;this.subprocessManager=null;this.config=e}static parseConfig(){let e=r.values.extensions;return{dbPath:r.values.db,port:parseInt(r.values.port,10),host:r.values.host,path:r.values.path,debugLevel:parseInt(r.values.debug,10),extensionNames:e?e.split(",").map(o=>o.trim()):void 0,runCommand:r.values.run,includeDatabaseUrl:r.values["include-database-url"],shutdownTimeout:parseInt(r.values["shutdown-timeout"],10),maxConnections:parseInt(r.values["max-connections"],10)}}createDatabaseUrl(){let{host:e,port:o,path:t}=this.config;if(t){let s=t.endsWith("/.s.PGSQL.5432")?t.slice(0,-13):t;return`postgresql://postgres:postgres@/postgres?host=${encodeURIComponent(s)}`}else return`postgresql://postgres:postgres@${e}:${o}/postgres`}async importExtensions(){if(!this.config.extensionNames?.length)return;let e={},o=["vector","live","pg_hashids","pg_ivm","pg_uuidv7","pgtap","age","pg_textsearch"];for(let t of this.config.extensionNames){let s=null;try{if(t.includes(":")){let[i,n]=t.split(":");if(!i||!n)throw new Error(`Invalid extension format '${t}'. Expected: package/path:exportedName`);s=(await import(i))[n],s&&(e[n]=s,console.log(`Imported extension '${n}' from '${i}'`))}else if(o.includes(t))s=(await import(`@electric-sql/pglite/${t}`))[t],s&&(e[t]=s,console.log(`Imported extension: ${t}`));else{try{s=(await import(`@electric-sql/pglite/contrib/${t}`))[t]}catch{s=(await import(`@electric-sql/pglite-${t}`))[t]}s&&(e[t]=s,console.log(`Imported extension: ${t}`))}}catch(i){throw console.error(`Failed to import extension '${t}':`,i),new Error(`Failed to import extension '${t}'`)}}return Object.keys(e).length>0?e:void 0}async initializeDatabase(){console.log(`Initializing PGLite with database: ${this.config.dbPath}`),console.log(`Debug level: ${this.config.debugLevel}`);let e=await this.importExtensions();this.db=new u(this.config.dbPath,{debug:this.config.debugLevel,extensions:e}),await this.db.waitReady,console.log("PGlite database initialized")}setupServerEventHandlers(){if(!this.server||!this.subprocessManager)throw new Error("Server or subprocess manager not initialized");this.server.addEventListener("listening",e=>{let o=e.detail;if(console.log(`PGLiteSocketServer listening on ${JSON.stringify(o)}`),this.config.runCommand&&this.subprocessManager){let t=this.createDatabaseUrl();this.subprocessManager.spawn(this.config.runCommand,t,this.config.includeDatabaseUrl)}}),this.server.addEventListener("connection",e=>{let{clientAddress:o,clientPort:t}=e.detail;console.log(`Client connected from ${o}:${t}`)}),this.server.addEventListener("error",e=>{let o=e.detail;console.error("Socket server error:",o)})}setupSignalHandlers(){process.on("SIGINT",()=>this.shutdown()),process.on("SIGTERM",()=>this.shutdown())}async start(){try{if(await this.initializeDatabase(),!this.db)throw new Error("Database initialization failed");this.server=new d({db:this.db,port:this.config.port,host:this.config.host,path:this.config.path,inspect:this.config.debugLevel>0,maxConnections:this.config.maxConnections}),this.subprocessManager=new c(e=>{this.shutdown(e)}),this.setupServerEventHandlers(),this.setupSignalHandlers(),await this.server.start()}catch(e){throw console.error("Failed to start PGLiteSocketServer:",e),e}}async shutdown(e=0){console.log(`
Shutting down PGLiteSocketServer...`),this.subprocessManager&&this.subprocessManager.terminate(this.config.shutdownTimeout),this.server&&await this.server.stop(),this.db&&await this.db.close(),console.log("Server stopped"),process.exit(e)}},c=class{constructor(e){this.childProcess=null;this.onExit=e}get process(){return this.childProcess}spawn(e,o,t){console.log(`Running command: ${e}`);let s={...process.env};t&&(s.DATABASE_URL=o,console.log(`Setting DATABASE_URL=${o}`));let i=e.trim().split(/\s+/);this.childProcess=p(i[0],i.slice(1),{env:s,stdio:"inherit"}),this.childProcess.on("error",n=>{console.error("Error running command:",n),console.log("Subprocess failed to start, shutting down..."),this.onExit(1)}),this.childProcess.on("close",n=>{console.log(`Command exited with code ${n}`),this.childProcess=null,n!==null&&n!==0&&(console.log(`Child process failed with exit code ${n}, shutting down...`),this.onExit(n))})}terminate(e){this.childProcess&&(console.log("Terminating child process..."),this.childProcess.kill("SIGTERM"),setTimeout(()=>{this.childProcess&&!this.childProcess.killed&&(console.log("Force killing child process..."),this.childProcess.kill("SIGKILL"))},e))}};async function m(){r.values.help&&(console.log(g),process.exit(0));try{let a=l.parseConfig();await new l(a).start()}catch(a){console.error("Unhandled error:",a),process.exit(1)}}m();
//# sourceMappingURL=server.js.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../src/scripts/server.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { PGlite, DebugLevel } from '@electric-sql/pglite'\nimport type { Extension, Extensions } from '@electric-sql/pglite'\nimport { PGLiteSocketServer } from '../index'\nimport { parseArgs } from 'node:util'\nimport { spawn, ChildProcess } from 'node:child_process'\n\n// Define command line argument options\nconst args = parseArgs({\n options: {\n db: {\n type: 'string',\n short: 'd',\n default: 'memory://',\n help: 'Database path (relative or absolute). Use memory:// for in-memory database.',\n },\n port: {\n type: 'string',\n short: 'p',\n default: '5432',\n help: 'Port to listen on',\n },\n host: {\n type: 'string',\n short: 'h',\n default: '127.0.0.1',\n help: 'Host to bind to',\n },\n path: {\n type: 'string',\n short: 'u',\n default: undefined,\n help: 'unix socket to bind to. Takes precedence over host:port',\n },\n debug: {\n type: 'string',\n short: 'v',\n default: '0',\n help: 'Debug level (0-5)',\n },\n extensions: {\n type: 'string',\n short: 'e',\n default: undefined,\n help: 'Comma-separated list of extensions to load (e.g., vector,pgcrypto)',\n },\n run: {\n type: 'string',\n short: 'r',\n default: undefined,\n help: 'Command to run after server starts',\n },\n 'include-database-url': {\n type: 'boolean',\n default: false,\n help: 'Include DATABASE_URL in the environment of the subprocess',\n },\n 'shutdown-timeout': {\n type: 'string',\n default: '5000',\n help: 'Timeout in milliseconds for graceful subprocess shutdown (default: 5000)',\n },\n 'max-connections': {\n type: 'string',\n short: 'm',\n default: '1',\n help: 'Maximum concurrent connections (default: 1)',\n },\n help: {\n type: 'boolean',\n short: '?',\n default: false,\n help: 'Show help',\n },\n },\n})\n\nconst help = `PGlite Socket Server\nUsage: pglite-server [options]\n\nOptions:\n -d, --db=PATH Database path (default: memory://)\n -p, --port=PORT Port to listen on (default: 5432)\n -h, --host=HOST Host to bind to (default: 127.0.0.1)\n -u, --path=UNIX Unix socket to bind to (default: undefined). Takes precedence over host:port\n -v, --debug=LEVEL Debug level 0-5 (default: 0)\n -e, --extensions=LIST Comma-separated list of extensions to load\n Formats: vector, pgcrypto (built-in/contrib)\n @org/package/path:exportedName (npm package)\n -r, --run=COMMAND Command to run after server starts\n --include-database-url Include DATABASE_URL in subprocess environment\n --shutdown-timeout=MS Timeout for graceful subprocess shutdown in ms (default: 5000)\n -m, --max-connections=N Maximum concurrent connections (default is no concurrency: 1)\n`\n\ninterface ServerConfig {\n dbPath: string\n port: number\n host: string\n path?: string\n debugLevel: DebugLevel\n extensionNames?: string[]\n runCommand?: string\n includeDatabaseUrl: boolean\n shutdownTimeout: number\n maxConnections: number\n}\n\nclass PGLiteServerRunner {\n private config: ServerConfig\n private db: PGlite | null = null\n private server: PGLiteSocketServer | null = null\n private subprocessManager: SubprocessManager | null = null\n\n constructor(config: ServerConfig) {\n this.config = config\n }\n\n static parseConfig(): ServerConfig {\n const extensionsArg = args.values.extensions as string | undefined\n return {\n dbPath: args.values.db as string,\n port: parseInt(args.values.port as string, 10),\n host: args.values.host as string,\n path: args.values.path as string,\n debugLevel: parseInt(args.values.debug as string, 10) as DebugLevel,\n extensionNames: extensionsArg\n ? extensionsArg.split(',').map((e) => e.trim())\n : undefined,\n runCommand: args.values.run as string,\n includeDatabaseUrl: args.values['include-database-url'] as boolean,\n shutdownTimeout: parseInt(args.values['shutdown-timeout'] as string, 10),\n maxConnections: parseInt(args.values['max-connections'] as string, 10),\n }\n }\n\n private createDatabaseUrl(): string {\n const { host, port, path } = this.config\n\n if (path) {\n // Unix socket connection\n const socketDir = path.endsWith('/.s.PGSQL.5432')\n ? path.slice(0, -13)\n : path\n return `postgresql://postgres:postgres@/postgres?host=${encodeURIComponent(socketDir)}`\n } else {\n // TCP connection\n return `postgresql://postgres:postgres@${host}:${port}/postgres`\n }\n }\n\n private async importExtensions(): Promise<Extensions | undefined> {\n if (!this.config.extensionNames?.length) {\n return undefined\n }\n\n const extensions: Extensions = {}\n\n // Built-in extensions that are not in contrib\n const builtInExtensions = [\n 'vector',\n 'live',\n 'pg_hashids',\n 'pg_ivm',\n 'pg_uuidv7',\n 'pgtap',\n ]\n\n for (const name of this.config.extensionNames) {\n let ext: Extension | null = null\n\n try {\n // Check if this is a custom package path (contains ':')\n // Format: @org/package/path:exportedName or package/path:exportedName\n if (name.includes(':')) {\n const [packagePath, exportName] = name.split(':')\n if (!packagePath || !exportName) {\n throw new Error(\n `Invalid extension format '${name}'. Expected: package/path:exportedName`,\n )\n }\n const mod = await import(packagePath)\n ext = mod[exportName] as Extension\n if (ext) {\n extensions[exportName] = ext\n console.log(\n `Imported extension '${exportName}' from '${packagePath}'`,\n )\n }\n } else if (builtInExtensions.includes(name)) {\n // Built-in extension (e.g., @electric-sql/pglite/vector)\n const mod = await import(`@electric-sql/pglite/${name}`)\n ext = mod[name] as Extension\n if (ext) {\n extensions[name] = ext\n console.log(`Imported extension: ${name}`)\n }\n } else {\n // Try contrib first (e.g., @electric-sql/pglite/contrib/pgcrypto)\n try {\n const mod = await import(`@electric-sql/pglite/contrib/${name}`)\n ext = mod[name] as Extension\n } catch {\n // Fall back to external package (e.g., @electric-sql/pglite-<extension>)\n const mod = await import(`@electric-sql/pglite-${name}`)\n ext = mod[name] as Extension\n }\n if (ext) {\n extensions[name] = ext\n console.log(`Imported extension: ${name}`)\n }\n }\n } catch (error) {\n console.error(`Failed to import extension '${name}':`, error)\n throw new Error(`Failed to import extension '${name}'`)\n }\n }\n\n return Object.keys(extensions).length > 0 ? extensions : undefined\n }\n\n private async initializeDatabase(): Promise<void> {\n console.log(`Initializing PGLite with database: ${this.config.dbPath}`)\n console.log(`Debug level: ${this.config.debugLevel}`)\n\n const extensions = await this.importExtensions()\n\n this.db = new PGlite(this.config.dbPath, {\n debug: this.config.debugLevel,\n extensions,\n })\n await this.db.waitReady\n console.log('PGlite database initialized')\n }\n\n private setupServerEventHandlers(): void {\n if (!this.server || !this.subprocessManager) {\n throw new Error('Server or subprocess manager not initialized')\n }\n\n this.server.addEventListener('listening', (event) => {\n const detail = (\n event as CustomEvent<{ port: number; host: string } | { host: string }>\n ).detail\n console.log(`PGLiteSocketServer listening on ${JSON.stringify(detail)}`)\n\n // Run the command after server starts listening\n if (this.config.runCommand && this.subprocessManager) {\n const databaseUrl = this.createDatabaseUrl()\n this.subprocessManager.spawn(\n this.config.runCommand,\n databaseUrl,\n this.config.includeDatabaseUrl,\n )\n }\n })\n\n this.server.addEventListener('connection', (event) => {\n const { clientAddress, clientPort } = (\n event as CustomEvent<{ clientAddress: string; clientPort: number }>\n ).detail\n console.log(`Client connected from ${clientAddress}:${clientPort}`)\n })\n\n this.server.addEventListener('error', (event) => {\n const error = (event as CustomEvent<Error>).detail\n console.error('Socket server error:', error)\n })\n }\n\n private setupSignalHandlers(): void {\n process.on('SIGINT', () => this.shutdown())\n process.on('SIGTERM', () => this.shutdown())\n }\n\n async start(): Promise<void> {\n try {\n // Initialize database\n await this.initializeDatabase()\n\n if (!this.db) {\n throw new Error('Database initialization failed')\n }\n\n // Create and setup the socket server\n this.server = new PGLiteSocketServer({\n db: this.db,\n port: this.config.port,\n host: this.config.host,\n path: this.config.path,\n inspect: this.config.debugLevel > 0,\n maxConnections: this.config.maxConnections,\n })\n\n // Create subprocess manager\n this.subprocessManager = new SubprocessManager((exitCode) => {\n this.shutdown(exitCode)\n })\n\n // Setup event handlers\n this.setupServerEventHandlers()\n this.setupSignalHandlers()\n\n // Start the server\n await this.server.start()\n } catch (error) {\n console.error('Failed to start PGLiteSocketServer:', error)\n throw error\n }\n }\n\n async shutdown(exitCode: number = 0): Promise<void> {\n console.log('\\nShutting down PGLiteSocketServer...')\n\n // Terminate subprocess if running\n if (this.subprocessManager) {\n this.subprocessManager.terminate(this.config.shutdownTimeout)\n }\n\n // Stop server\n if (this.server) {\n await this.server.stop()\n }\n\n // Close database\n if (this.db) {\n await this.db.close()\n }\n\n console.log('Server stopped')\n process.exit(exitCode)\n }\n}\n\nclass SubprocessManager {\n private childProcess: ChildProcess | null = null\n private onExit: (code: number) => void\n\n constructor(onExit: (code: number) => void) {\n this.onExit = onExit\n }\n\n get process(): ChildProcess | null {\n return this.childProcess\n }\n\n spawn(\n command: string,\n databaseUrl: string,\n includeDatabaseUrl: boolean,\n ): void {\n console.log(`Running command: ${command}`)\n\n // Prepare environment variables\n const env = { ...process.env }\n if (includeDatabaseUrl) {\n env.DATABASE_URL = databaseUrl\n console.log(`Setting DATABASE_URL=${databaseUrl}`)\n }\n\n // Parse and spawn the command\n const commandParts = command.trim().split(/\\s+/)\n this.childProcess = spawn(commandParts[0], commandParts.slice(1), {\n env,\n stdio: 'inherit',\n })\n\n this.childProcess.on('error', (error) => {\n console.error('Error running command:', error)\n // If subprocess fails to start, shutdown the server\n console.log('Subprocess failed to start, shutting down...')\n this.onExit(1)\n })\n\n this.childProcess.on('close', (code) => {\n console.log(`Command exited with code ${code}`)\n this.childProcess = null\n\n // If child process exits with non-zero code, notify parent\n if (code !== null && code !== 0) {\n console.log(\n `Child process failed with exit code ${code}, shutting down...`,\n )\n this.onExit(code)\n }\n })\n }\n\n terminate(timeout: number): void {\n if (this.childProcess) {\n console.log('Terminating child process...')\n this.childProcess.kill('SIGTERM')\n\n // Give it a moment to exit gracefully, then force kill if needed\n setTimeout(() => {\n if (this.childProcess && !this.childProcess.killed) {\n console.log('Force killing child process...')\n this.childProcess.kill('SIGKILL')\n }\n }, timeout)\n }\n }\n}\n\n// Main execution\nasync function main() {\n // Show help and exit if requested\n if (args.values.help) {\n console.log(help)\n process.exit(0)\n }\n\n try {\n const config = PGLiteServerRunner.parseConfig()\n const serverRunner = new PGLiteServerRunner(config)\n await serverRunner.start()\n } catch (error) {\n console.error('Unhandled error:', error)\n process.exit(1)\n }\n}\n\n// Run the main function\nmain()\n"],"mappings":";yCAEA,OAAS,UAAAA,MAA0B,uBAGnC,OAAS,aAAAC,MAAiB,YAC1B,OAAS,SAAAC,MAA2B,qBAGpC,IAAMC,EAAOF,EAAU,CACrB,QAAS,CACP,GAAI,CACF,KAAM,SACN,MAAO,IACP,QAAS,YACT,KAAM,6EACR,EACA,KAAM,CACJ,KAAM,SACN,MAAO,IACP,QAAS,OACT,KAAM,mBACR,EACA,KAAM,CACJ,KAAM,SACN,MAAO,IACP,QAAS,YACT,KAAM,iBACR,EACA,KAAM,CACJ,KAAM,SACN,MAAO,IACP,QAAS,OACT,KAAM,yDACR,EACA,MAAO,CACL,KAAM,SACN,MAAO,IACP,QAAS,IACT,KAAM,mBACR,EACA,WAAY,CACV,KAAM,SACN,MAAO,IACP,QAAS,OACT,KAAM,oEACR,EACA,IAAK,CACH,KAAM,SACN,MAAO,IACP,QAAS,OACT,KAAM,oCACR,EACA,uBAAwB,CACtB,KAAM,UACN,QAAS,GACT,KAAM,2DACR,EACA,mBAAoB,CAClB,KAAM,SACN,QAAS,OACT,KAAM,0EACR,EACA,kBAAmB,CACjB,KAAM,SACN,MAAO,IACP,QAAS,IACT,KAAM,6CACR,EACA,KAAM,CACJ,KAAM,UACN,MAAO,IACP,QAAS,GACT,KAAM,WACR,CACF,CACF,CAAC,EAEKG,EAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA+BPC,EAAN,KAAyB,CAMvB,YAAYC,EAAsB,CAJlC,KAAQ,GAAoB,KAC5B,KAAQ,OAAoC,KAC5C,KAAQ,kBAA8C,KAGpD,KAAK,OAASA,CAChB,CAEA,OAAO,aAA4B,CACjC,IAAMC,EAAgBJ,EAAK,OAAO,WAClC,MAAO,CACL,OAAQA,EAAK,OAAO,GACpB,KAAM,SAASA,EAAK,OAAO,KAAgB,EAAE,EAC7C,KAAMA,EAAK,OAAO,KAClB,KAAMA,EAAK,OAAO,KAClB,WAAY,SAASA,EAAK,OAAO,MAAiB,EAAE,EACpD,eAAgBI,EACZA,EAAc,MAAM,GAAG,EAAE,IAAKC,GAAMA,EAAE,KAAK,CAAC,EAC5C,OACJ,WAAYL,EAAK,OAAO,IACxB,mBAAoBA,EAAK,OAAO,sBAAsB,EACtD,gBAAiB,SAASA,EAAK,OAAO,kBAAkB,EAAa,EAAE,EACvE,eAAgB,SAASA,EAAK,OAAO,iBAAiB,EAAa,EAAE,CACvE,CACF,CAEQ,mBAA4B,CAClC,GAAM,CAAE,KAAAM,EAAM,KAAAC,EAAM,KAAAC,CAAK,EAAI,KAAK,OAElC,GAAIA,EAAM,CAER,IAAMC,EAAYD,EAAK,SAAS,gBAAgB,EAC5CA,EAAK,MAAM,EAAG,GAAG,EACjBA,EACJ,MAAO,iDAAiD,mBAAmBC,CAAS,CAAC,EACvF,KAEE,OAAO,kCAAkCH,CAAI,IAAIC,CAAI,WAEzD,CAEA,MAAc,kBAAoD,CAChE,GAAI,CAAC,KAAK,OAAO,gBAAgB,OAC/B,OAGF,IAAMG,EAAyB,CAAC,EAG1BC,EAAoB,CACxB,SACA,OACA,aACA,SACA,YACA,OACF,EAEA,QAAWC,KAAQ,KAAK,OAAO,eAAgB,CAC7C,IAAIC,EAAwB,KAE5B,GAAI,CAGF,GAAID,EAAK,SAAS,GAAG,EAAG,CACtB,GAAM,CAACE,EAAaC,CAAU,EAAIH,EAAK,MAAM,GAAG,EAChD,GAAI,CAACE,GAAe,CAACC,EACnB,MAAM,IAAI,MACR,6BAA6BH,CAAI,wCACnC,EAGFC,GADY,MAAM,OAAOC,IACfC,CAAU,EAChBF,IACFH,EAAWK,CAAU,EAAIF,EACzB,QAAQ,IACN,uBAAuBE,CAAU,WAAWD,CAAW,GACzD,EAEJ,SAAWH,EAAkB,SAASC,CAAI,EAGxCC,GADY,MAAM,OAAO,wBAAwBD,CAAI,KAC3CA,CAAI,EACVC,IACFH,EAAWE,CAAI,EAAIC,EACnB,QAAQ,IAAI,uBAAuBD,CAAI,EAAE,OAEtC,CAEL,GAAI,CAEFC,GADY,MAAM,OAAO,gCAAgCD,CAAI,KACnDA,CAAI,CAChB,MAAQ,CAGNC,GADY,MAAM,OAAO,wBAAwBD,CAAI,KAC3CA,CAAI,CAChB,CACIC,IACFH,EAAWE,CAAI,EAAIC,EACnB,QAAQ,IAAI,uBAAuBD,CAAI,EAAE,EAE7C,CACF,OAASI,EAAO,CACd,cAAQ,MAAM,+BAA+BJ,CAAI,KAAMI,CAAK,EACtD,IAAI,MAAM,+BAA+BJ,CAAI,GAAG,CACxD,CACF,CAEA,OAAO,OAAO,KAAKF,CAAU,EAAE,OAAS,EAAIA,EAAa,MAC3D,CAEA,MAAc,oBAAoC,CAChD,QAAQ,IAAI,sCAAsC,KAAK,OAAO,MAAM,EAAE,EACtE,QAAQ,IAAI,gBAAgB,KAAK,OAAO,UAAU,EAAE,EAEpD,IAAMA,EAAa,MAAM,KAAK,iBAAiB,EAE/C,KAAK,GAAK,IAAIO,EAAO,KAAK,OAAO,OAAQ,CACvC,MAAO,KAAK,OAAO,WACnB,WAAAP,CACF,CAAC,EACD,MAAM,KAAK,GAAG,UACd,QAAQ,IAAI,6BAA6B,CAC3C,CAEQ,0BAAiC,CACvC,GAAI,CAAC,KAAK,QAAU,CAAC,KAAK,kBACxB,MAAM,IAAI,MAAM,8CAA8C,EAGhE,KAAK,OAAO,iBAAiB,YAAcQ,GAAU,CACnD,IAAMC,EACJD,EACA,OAIF,GAHA,QAAQ,IAAI,mCAAmC,KAAK,UAAUC,CAAM,CAAC,EAAE,EAGnE,KAAK,OAAO,YAAc,KAAK,kBAAmB,CACpD,IAAMC,EAAc,KAAK,kBAAkB,EAC3C,KAAK,kBAAkB,MACrB,KAAK,OAAO,WACZA,EACA,KAAK,OAAO,kBACd,CACF,CACF,CAAC,EAED,KAAK,OAAO,iBAAiB,aAAeF,GAAU,CACpD,GAAM,CAAE,cAAAG,EAAe,WAAAC,CAAW,EAChCJ,EACA,OACF,QAAQ,IAAI,yBAAyBG,CAAa,IAAIC,CAAU,EAAE,CACpE,CAAC,EAED,KAAK,OAAO,iBAAiB,QAAUJ,GAAU,CAC/C,IAAMF,EAASE,EAA6B,OAC5C,QAAQ,MAAM,uBAAwBF,CAAK,CAC7C,CAAC,CACH,CAEQ,qBAA4B,CAClC,QAAQ,GAAG,SAAU,IAAM,KAAK,SAAS,CAAC,EAC1C,QAAQ,GAAG,UAAW,IAAM,KAAK,SAAS,CAAC,CAC7C,CAEA,MAAM,OAAuB,CAC3B,GAAI,CAIF,GAFA,MAAM,KAAK,mBAAmB,EAE1B,CAAC,KAAK,GACR,MAAM,IAAI,MAAM,gCAAgC,EAIlD,KAAK,OAAS,IAAIO,EAAmB,CACnC,GAAI,KAAK,GACT,KAAM,KAAK,OAAO,KAClB,KAAM,KAAK,OAAO,KAClB,KAAM,KAAK,OAAO,KAClB,QAAS,KAAK,OAAO,WAAa,EAClC,eAAgB,KAAK,OAAO,cAC9B,CAAC,EAGD,KAAK,kBAAoB,IAAIC,EAAmBC,GAAa,CAC3D,KAAK,SAASA,CAAQ,CACxB,CAAC,EAGD,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EAGzB,MAAM,KAAK,OAAO,MAAM,CAC1B,OAAST,EAAO,CACd,cAAQ,MAAM,sCAAuCA,CAAK,EACpDA,CACR,CACF,CAEA,MAAM,SAASS,EAAmB,EAAkB,CAClD,QAAQ,IAAI;AAAA,oCAAuC,EAG/C,KAAK,mBACP,KAAK,kBAAkB,UAAU,KAAK,OAAO,eAAe,EAI1D,KAAK,QACP,MAAM,KAAK,OAAO,KAAK,EAIrB,KAAK,IACP,MAAM,KAAK,GAAG,MAAM,EAGtB,QAAQ,IAAI,gBAAgB,EAC5B,QAAQ,KAAKA,CAAQ,CACvB,CACF,EAEMD,EAAN,KAAwB,CAItB,YAAYE,EAAgC,CAH5C,KAAQ,aAAoC,KAI1C,KAAK,OAASA,CAChB,CAEA,IAAI,SAA+B,CACjC,OAAO,KAAK,YACd,CAEA,MACEC,EACAP,EACAQ,EACM,CACN,QAAQ,IAAI,oBAAoBD,CAAO,EAAE,EAGzC,IAAME,EAAM,CAAE,GAAG,QAAQ,GAAI,EACzBD,IACFC,EAAI,aAAeT,EACnB,QAAQ,IAAI,wBAAwBA,CAAW,EAAE,GAInD,IAAMU,EAAeH,EAAQ,KAAK,EAAE,MAAM,KAAK,EAC/C,KAAK,aAAe5B,EAAM+B,EAAa,CAAC,EAAGA,EAAa,MAAM,CAAC,EAAG,CAChE,IAAAD,EACA,MAAO,SACT,CAAC,EAED,KAAK,aAAa,GAAG,QAAUb,GAAU,CACvC,QAAQ,MAAM,yBAA0BA,CAAK,EAE7C,QAAQ,IAAI,8CAA8C,EAC1D,KAAK,OAAO,CAAC,CACf,CAAC,EAED,KAAK,aAAa,GAAG,QAAUe,GAAS,CACtC,QAAQ,IAAI,4BAA4BA,CAAI,EAAE,EAC9C,KAAK,aAAe,KAGhBA,IAAS,MAAQA,IAAS,IAC5B,QAAQ,IACN,uCAAuCA,CAAI,oBAC7C,EACA,KAAK,OAAOA,CAAI,EAEpB,CAAC,CACH,CAEA,UAAUC,EAAuB,CAC3B,KAAK,eACP,QAAQ,IAAI,8BAA8B,EAC1C,KAAK,aAAa,KAAK,SAAS,EAGhC,WAAW,IAAM,CACX,KAAK,cAAgB,CAAC,KAAK,aAAa,SAC1C,QAAQ,IAAI,gCAAgC,EAC5C,KAAK,aAAa,KAAK,SAAS,EAEpC,EAAGA,CAAO,EAEd,CACF,EAGA,eAAeC,GAAO,CAEhBjC,EAAK,OAAO,OACd,QAAQ,IAAIC,CAAI,EAChB,QAAQ,KAAK,CAAC,GAGhB,GAAI,CACF,IAAME,EAASD,EAAmB,YAAY,EAE9C,MADqB,IAAIA,EAAmBC,CAAM,EAC/B,MAAM,CAC3B,OAASa,EAAO,CACd,QAAQ,MAAM,mBAAoBA,CAAK,EACvC,QAAQ,KAAK,CAAC,CAChB,CACF,CAGAiB,EAAK","names":["PGlite","parseArgs","spawn","args","help","PGLiteServerRunner","config","extensionsArg","e","host","port","path","socketDir","extensions","builtInExtensions","name","ext","packagePath","exportName","error","PGlite","event","detail","databaseUrl","clientAddress","clientPort","PGLiteSocketServer","SubprocessManager","exitCode","onExit","command","includeDatabaseUrl","env","commandParts","code","timeout","main"]}
{"version":3,"sources":["../../src/scripts/server.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { PGlite, DebugLevel } from '@electric-sql/pglite'\nimport type { Extension, Extensions } from '@electric-sql/pglite'\nimport { PGLiteSocketServer } from '../index'\nimport { parseArgs } from 'node:util'\nimport { spawn, ChildProcess } from 'node:child_process'\n\n// Define command line argument options\nconst args = parseArgs({\n options: {\n db: {\n type: 'string',\n short: 'd',\n default: 'memory://',\n help: 'Database path (relative or absolute). Use memory:// for in-memory database.',\n },\n port: {\n type: 'string',\n short: 'p',\n default: '5432',\n help: 'Port to listen on',\n },\n host: {\n type: 'string',\n short: 'h',\n default: '127.0.0.1',\n help: 'Host to bind to',\n },\n path: {\n type: 'string',\n short: 'u',\n default: undefined,\n help: 'unix socket to bind to. Takes precedence over host:port',\n },\n debug: {\n type: 'string',\n short: 'v',\n default: '0',\n help: 'Debug level (0-5)',\n },\n extensions: {\n type: 'string',\n short: 'e',\n default: undefined,\n help: 'Comma-separated list of extensions to load (e.g., vector,pgcrypto,postgis etc.)',\n },\n run: {\n type: 'string',\n short: 'r',\n default: undefined,\n help: 'Command to run after server starts',\n },\n 'include-database-url': {\n type: 'boolean',\n default: false,\n help: 'Include DATABASE_URL in the environment of the subprocess',\n },\n 'shutdown-timeout': {\n type: 'string',\n default: '5000',\n help: 'Timeout in milliseconds for graceful subprocess shutdown (default: 5000)',\n },\n 'max-connections': {\n type: 'string',\n short: 'm',\n default: '1',\n help: 'Maximum concurrent connections (default: 1)',\n },\n help: {\n type: 'boolean',\n short: '?',\n default: false,\n help: 'Show help',\n },\n },\n})\n\nconst help = `PGlite Socket Server\nUsage: pglite-server [options]\n\nOptions:\n -d, --db=PATH Database path (default: memory://)\n -p, --port=PORT Port to listen on (default: 5432)\n -h, --host=HOST Host to bind to (default: 127.0.0.1)\n -u, --path=UNIX Unix socket to bind to (default: undefined). Takes precedence over host:port\n -v, --debug=LEVEL Debug level 0-5 (default: 0)\n -e, --extensions=LIST Comma-separated list of extensions to load\n Formats: vector, pgcrypto (built-in/contrib)\n @org/package/path:exportedName (npm package)\n -r, --run=COMMAND Command to run after server starts\n --include-database-url Include DATABASE_URL in subprocess environment\n --shutdown-timeout=MS Timeout for graceful subprocess shutdown in ms (default: 5000)\n -m, --max-connections=N Maximum concurrent connections (default is no concurrency: 1)\n`\n\ninterface ServerConfig {\n dbPath: string\n port: number\n host: string\n path?: string\n debugLevel: DebugLevel\n extensionNames?: string[]\n runCommand?: string\n includeDatabaseUrl: boolean\n shutdownTimeout: number\n maxConnections: number\n}\n\nclass PGLiteServerRunner {\n private config: ServerConfig\n private db: PGlite | null = null\n private server: PGLiteSocketServer | null = null\n private subprocessManager: SubprocessManager | null = null\n\n constructor(config: ServerConfig) {\n this.config = config\n }\n\n static parseConfig(): ServerConfig {\n const extensionsArg = args.values.extensions as string | undefined\n return {\n dbPath: args.values.db as string,\n port: parseInt(args.values.port as string, 10),\n host: args.values.host as string,\n path: args.values.path as string,\n debugLevel: parseInt(args.values.debug as string, 10) as DebugLevel,\n extensionNames: extensionsArg\n ? extensionsArg.split(',').map((e) => e.trim())\n : undefined,\n runCommand: args.values.run as string,\n includeDatabaseUrl: args.values['include-database-url'] as boolean,\n shutdownTimeout: parseInt(args.values['shutdown-timeout'] as string, 10),\n maxConnections: parseInt(args.values['max-connections'] as string, 10),\n }\n }\n\n private createDatabaseUrl(): string {\n const { host, port, path } = this.config\n\n if (path) {\n // Unix socket connection\n const socketDir = path.endsWith('/.s.PGSQL.5432')\n ? path.slice(0, -13)\n : path\n return `postgresql://postgres:postgres@/postgres?host=${encodeURIComponent(socketDir)}`\n } else {\n // TCP connection\n return `postgresql://postgres:postgres@${host}:${port}/postgres`\n }\n }\n\n private async importExtensions(): Promise<Extensions | undefined> {\n if (!this.config.extensionNames?.length) {\n return undefined\n }\n\n const extensions: Extensions = {}\n\n // Built-in extensions that are not in contrib\n const builtInExtensions = [\n 'vector',\n 'live',\n 'pg_hashids',\n 'pg_ivm',\n 'pg_uuidv7',\n 'pgtap',\n 'age',\n 'pg_textsearch',\n ]\n\n for (const name of this.config.extensionNames) {\n let ext: Extension | null = null\n\n try {\n // Check if this is a custom package path (contains ':')\n // Format: @org/package/path:exportedName or package/path:exportedName\n if (name.includes(':')) {\n const [packagePath, exportName] = name.split(':')\n if (!packagePath || !exportName) {\n throw new Error(\n `Invalid extension format '${name}'. Expected: package/path:exportedName`,\n )\n }\n const mod = await import(packagePath)\n ext = mod[exportName] as Extension\n if (ext) {\n extensions[exportName] = ext\n console.log(\n `Imported extension '${exportName}' from '${packagePath}'`,\n )\n }\n } else if (builtInExtensions.includes(name)) {\n // Built-in extension (e.g., @electric-sql/pglite/vector)\n const mod = await import(`@electric-sql/pglite/${name}`)\n ext = mod[name] as Extension\n if (ext) {\n extensions[name] = ext\n console.log(`Imported extension: ${name}`)\n }\n } else {\n // Try contrib first (e.g., @electric-sql/pglite/contrib/pgcrypto)\n try {\n const mod = await import(`@electric-sql/pglite/contrib/${name}`)\n ext = mod[name] as Extension\n } catch {\n // Fall back to external package (e.g., @electric-sql/pglite-<extension>)\n const mod = await import(`@electric-sql/pglite-${name}`)\n ext = mod[name] as Extension\n }\n if (ext) {\n extensions[name] = ext\n console.log(`Imported extension: ${name}`)\n }\n }\n } catch (error) {\n console.error(`Failed to import extension '${name}':`, error)\n throw new Error(`Failed to import extension '${name}'`)\n }\n }\n\n return Object.keys(extensions).length > 0 ? extensions : undefined\n }\n\n private async initializeDatabase(): Promise<void> {\n console.log(`Initializing PGLite with database: ${this.config.dbPath}`)\n console.log(`Debug level: ${this.config.debugLevel}`)\n\n const extensions = await this.importExtensions()\n\n this.db = new PGlite(this.config.dbPath, {\n debug: this.config.debugLevel,\n extensions,\n })\n await this.db.waitReady\n console.log('PGlite database initialized')\n }\n\n private setupServerEventHandlers(): void {\n if (!this.server || !this.subprocessManager) {\n throw new Error('Server or subprocess manager not initialized')\n }\n\n this.server.addEventListener('listening', (event) => {\n const detail = (\n event as CustomEvent<{ port: number; host: string } | { host: string }>\n ).detail\n console.log(`PGLiteSocketServer listening on ${JSON.stringify(detail)}`)\n\n // Run the command after server starts listening\n if (this.config.runCommand && this.subprocessManager) {\n const databaseUrl = this.createDatabaseUrl()\n this.subprocessManager.spawn(\n this.config.runCommand,\n databaseUrl,\n this.config.includeDatabaseUrl,\n )\n }\n })\n\n this.server.addEventListener('connection', (event) => {\n const { clientAddress, clientPort } = (\n event as CustomEvent<{ clientAddress: string; clientPort: number }>\n ).detail\n console.log(`Client connected from ${clientAddress}:${clientPort}`)\n })\n\n this.server.addEventListener('error', (event) => {\n const error = (event as CustomEvent<Error>).detail\n console.error('Socket server error:', error)\n })\n }\n\n private setupSignalHandlers(): void {\n process.on('SIGINT', () => this.shutdown())\n process.on('SIGTERM', () => this.shutdown())\n }\n\n async start(): Promise<void> {\n try {\n // Initialize database\n await this.initializeDatabase()\n\n if (!this.db) {\n throw new Error('Database initialization failed')\n }\n\n // Create and setup the socket server\n this.server = new PGLiteSocketServer({\n db: this.db,\n port: this.config.port,\n host: this.config.host,\n path: this.config.path,\n inspect: this.config.debugLevel > 0,\n maxConnections: this.config.maxConnections,\n })\n\n // Create subprocess manager\n this.subprocessManager = new SubprocessManager((exitCode) => {\n this.shutdown(exitCode)\n })\n\n // Setup event handlers\n this.setupServerEventHandlers()\n this.setupSignalHandlers()\n\n // Start the server\n await this.server.start()\n } catch (error) {\n console.error('Failed to start PGLiteSocketServer:', error)\n throw error\n }\n }\n\n async shutdown(exitCode: number = 0): Promise<void> {\n console.log('\\nShutting down PGLiteSocketServer...')\n\n // Terminate subprocess if running\n if (this.subprocessManager) {\n this.subprocessManager.terminate(this.config.shutdownTimeout)\n }\n\n // Stop server\n if (this.server) {\n await this.server.stop()\n }\n\n // Close database\n if (this.db) {\n await this.db.close()\n }\n\n console.log('Server stopped')\n process.exit(exitCode)\n }\n}\n\nclass SubprocessManager {\n private childProcess: ChildProcess | null = null\n private onExit: (code: number) => void\n\n constructor(onExit: (code: number) => void) {\n this.onExit = onExit\n }\n\n get process(): ChildProcess | null {\n return this.childProcess\n }\n\n spawn(\n command: string,\n databaseUrl: string,\n includeDatabaseUrl: boolean,\n ): void {\n console.log(`Running command: ${command}`)\n\n // Prepare environment variables\n const env = { ...process.env }\n if (includeDatabaseUrl) {\n env.DATABASE_URL = databaseUrl\n console.log(`Setting DATABASE_URL=${databaseUrl}`)\n }\n\n // Parse and spawn the command\n const commandParts = command.trim().split(/\\s+/)\n this.childProcess = spawn(commandParts[0], commandParts.slice(1), {\n env,\n stdio: 'inherit',\n })\n\n this.childProcess.on('error', (error) => {\n console.error('Error running command:', error)\n // If subprocess fails to start, shutdown the server\n console.log('Subprocess failed to start, shutting down...')\n this.onExit(1)\n })\n\n this.childProcess.on('close', (code) => {\n console.log(`Command exited with code ${code}`)\n this.childProcess = null\n\n // If child process exits with non-zero code, notify parent\n if (code !== null && code !== 0) {\n console.log(\n `Child process failed with exit code ${code}, shutting down...`,\n )\n this.onExit(code)\n }\n })\n }\n\n terminate(timeout: number): void {\n if (this.childProcess) {\n console.log('Terminating child process...')\n this.childProcess.kill('SIGTERM')\n\n // Give it a moment to exit gracefully, then force kill if needed\n setTimeout(() => {\n if (this.childProcess && !this.childProcess.killed) {\n console.log('Force killing child process...')\n this.childProcess.kill('SIGKILL')\n }\n }, timeout)\n }\n }\n}\n\n// Main execution\nasync function main() {\n // Show help and exit if requested\n if (args.values.help) {\n console.log(help)\n process.exit(0)\n }\n\n try {\n const config = PGLiteServerRunner.parseConfig()\n const serverRunner = new PGLiteServerRunner(config)\n await serverRunner.start()\n } catch (error) {\n console.error('Unhandled error:', error)\n process.exit(1)\n }\n}\n\n// Run the main function\nmain()\n"],"mappings":"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","names":["PGlite","parseArgs","spawn","args","help","PGLiteServerRunner","config","extensionsArg","e","host","port","path","socketDir","extensions","builtInExtensions","name","ext","packagePath","exportName","error","PGlite","event","detail","databaseUrl","clientAddress","clientPort","PGLiteSocketServer","SubprocessManager","exitCode","onExit","command","includeDatabaseUrl","env","commandParts","code","timeout","main"]}
{
"name": "@electric-sql/pglite-socket",
"version": "0.0.22",
"version": "0.1.0",
"description": "A socket implementation for PGlite enabling remote connections",

@@ -53,6 +53,8 @@ "author": "Electric DB Limited",

"@electric-sql/pg-protocol": "0.0.4",
"@electric-sql/pglite": "0.3.16"
"@electric-sql/pglite": "0.4.0",
"@electric-sql/pglite-postgis": "0.0.1"
},
"peerDependencies": {
"@electric-sql/pglite": "0.3.16"
"@electric-sql/pglite": "0.4.0",
"@electric-sql/pglite-postgis": "0.0.1"
},

@@ -59,0 +61,0 @@ "scripts": {

@@ -13,5 +13,6 @@ import type { PGlite } from '@electric-sql/pglite'

message: Uint8Array
resolve: (result: Uint8Array) => void
resolve: (resultSize: number) => void
reject: (error: Error) => void
timestamp: number
onData: (data: Uint8Array) => void
}

@@ -41,3 +42,7 @@

async enqueue(handlerId: number, message: Uint8Array): Promise<Uint8Array> {
async enqueue(
handlerId: number,
message: Uint8Array,
onData: (data: Uint8Array) => void,
): Promise<number> {
return new Promise((resolve, reject) => {

@@ -50,2 +55,3 @@ const query: QueuedQuery = {

timestamp: Date.now(),
onData,
}

@@ -99,17 +105,24 @@

let result = 0
try {
// Execute the query with exclusive access to PGlite
const result = await this.db.runExclusive(async () => {
return await this.db.execProtocolRaw(query.message)
await this.db.runExclusive(async () => {
return await this.db.execProtocolRawStream(query.message, {
onRawData: (data) => {
result += data.length
query.onData(data)
},
})
})
this.log(
`query from handler #${query.handlerId} completed, ${result.length} bytes`,
)
this.lastHandlerId = query.handlerId
query.resolve(result)
} catch (error) {
this.log(`query from handler #${query.handlerId} failed:`, error)
query.reject(error as Error)
return
}
this.log(
`query from handler #${query.handlerId} completed, ${result} bytes`,
)
this.lastHandlerId = query.handlerId
query.resolve(result)
}

@@ -381,44 +394,40 @@

let socketWriteError: any = undefined
// Queue the query for execution
// This allows multiple connections to queue queries simultaneously
const result = await this.queryQueue.enqueue(
await this.queryQueue.enqueue(
this.id,
new Uint8Array(message),
)
(data) => {
this.log(`handleData: received ${data.length} bytes from PGlite`)
this.log(`handleData: received ${result.length} bytes from PGlite`)
// Print the outgoing data to the console
this.inspectData('outgoing', data)
// Print the outgoing data to the console
this.inspectData('outgoing', result)
// Send response if available
if (
result.length > 0 &&
this.socket &&
this.socket.writable &&
this.active
) {
await new Promise<number>((resolve, reject) => {
this.log(`handleData: writing response to socket`)
if (this.socket?.writable) {
this.socket.write(Buffer.from(result), (err?: any) => {
if (err) {
this.log(`handleData: error writing to socket:`, err)
reject(err)
} else {
this.log(`handleData: socket sent: ${result.length} bytes`)
resolve(result.length)
}
})
} else {
this.log(`handleData: socket no longer writable`)
resolve(0)
// Send response if available
if (
data.length > 0 &&
this.socket &&
this.socket.writable &&
this.active
) {
// await new Promise<number>((resolve, reject) => {
this.log(`handleData: writing response to socket`)
if (this.socket?.writable) {
this.socket.write(Buffer.from(data), (err?: any) => {
if (err) {
this.log(`handleData: error writing to socket:`, err)
socketWriteError = err
} else {
this.log(`handleData: socket sent: ${data.length} bytes`)
}
})
} else {
this.log(`handleData: socket no longer writable`)
}
}
}).catch((writeErr) => {
this.log(`handleData: failed to write to socket:`, writeErr)
throw writeErr
})
}
totalProcessed += result.length
totalProcessed += data.length
},
)
if (socketWriteError) throw socketWriteError
}

@@ -425,0 +434,0 @@

@@ -46,3 +46,3 @@ #!/usr/bin/env node

default: undefined,
help: 'Comma-separated list of extensions to load (e.g., vector,pgcrypto)',
help: 'Comma-separated list of extensions to load (e.g., vector,pgcrypto,postgis etc.)',
},

@@ -169,2 +169,4 @@ run: {

'pgtap',
'age',
'pg_textsearch',
]

@@ -171,0 +173,0 @@

import{createServer as f}from"net";var y=6e4,d=class{constructor(s,e=!1){this.queue=[];this.processing=!1;this.lastHandlerId=null;this.db=s,this.debug=e}log(s,...e){this.debug&&console.log(`[QueryQueueManager] ${s}`,...e)}async enqueue(s,e){return new Promise((t,i)=>{let r={handlerId:s,message:e,resolve:t,reject:i,timestamp:Date.now()};this.queue.push(r),this.log(`enqueued query from handler #${s}, queue size: ${this.queue.length}`),this.processing||this.processQueue()})}async processQueue(){if(!(this.processing||this.queue.length===0)){for(this.processing=!0;this.queue.length>0;){let s;if(this.db.isInTransaction()&&this.lastHandlerId){let t=this.queue.findIndex(i=>i.handlerId===this.lastHandlerId);t===-1?(this.log("transaction started, but no query from the same handler id found in queue",this.lastHandlerId),s=null):s=this.queue.splice(t,1)[0]}else s=this.queue.shift();if(!s)break;let e=Date.now()-s.timestamp;this.log(`processing query from handler #${s.handlerId} (waited ${e}ms)`);try{let t=await this.db.runExclusive(async()=>await this.db.execProtocolRaw(s.message));this.log(`query from handler #${s.handlerId} completed, ${t.length} bytes`),this.lastHandlerId=s.handlerId,s.resolve(t)}catch(t){this.log(`query from handler #${s.handlerId} failed:`,t),s.reject(t)}}this.processing=!1,this.log("queue processing complete, queue length is",this.queue.length)}}getQueueLength(){return this.queue.length}clearQueueForHandler(s){let e=this.queue.length;this.queue=this.queue.filter(i=>i.handlerId===s?(i.reject(new Error("Handler disconnected")),!1):!0);let t=e-this.queue.length;t>0&&this.log(`cleared ${t} queries for handler #${s}`)}async clearTransactionIfNeeded(s){this.db.isInTransaction()&&this.lastHandlerId===s&&(await this.db.exec("ROLLBACK"),this.lastHandlerId=null,await this.processQueue())}},l=class l extends EventTarget{constructor(e){super();this.socket=null;this.active=!1;this.messageBuffer=Buffer.alloc(0);this.lastActivityTime=Date.now();this.queryQueue=e.queryQueue,this.closeOnDetach=e.closeOnDetach??!1,this.inspect=e.inspect??!1,this.debug=e.debug??!1,this.idleTimeout=e.idleTimeout??0,this.id=l.nextHandlerId++,this.log("constructor: created new handler")}get handlerId(){return this.id}log(e,...t){this.debug&&console.log(`[PGLiteSocketHandler#${this.id}] ${e}`,...t)}async attach(e){if(this.log(`attach: attaching socket from ${e.remoteAddress}:${e.remotePort}`),this.socket)throw new Error("Socket already attached");return this.socket=e,this.active=!0,this.lastActivityTime=Date.now(),e.setNoDelay(!0),this.idleTimeout>0&&this.resetIdleTimer(),this.log("attach: setting up socket event handlers"),e.on("data",t=>{this.lastActivityTime=Date.now(),this.resetIdleTimer(),setImmediate(async()=>{try{await this.handleData(t)}catch(i){this.log("socket on data error: ",i),this.handleError(i)}})}),e.on("error",t=>{setImmediate(()=>this.handleError(t))}),e.on("close",()=>{setImmediate(()=>this.handleClose())}),this.log("attach: socket handler ready"),this}resetIdleTimer(){this.idleTimeout<=0||(this.idleTimer&&clearTimeout(this.idleTimer),this.idleTimer=setTimeout(()=>{let e=Date.now()-this.lastActivityTime;this.log(`idle timeout after ${e}ms`),this.handleError(new Error("Idle timeout"))},this.idleTimeout))}async detach(e){if(this.log(`detach: detaching socket, close=${e??this.closeOnDetach}`),this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=void 0),this.queryQueue.clearQueueForHandler(this.id),await this.queryQueue.clearTransactionIfNeeded(this.id),!this.socket)return this.log("detach: no socket attached, nothing to do"),this;if(this.socket.removeAllListeners("data"),this.socket.removeAllListeners("error"),this.socket.removeAllListeners("close"),(e??this.closeOnDetach)&&this.socket.writable){this.log("detach: closing socket");try{this.socket.end(),this.socket.destroy()}catch(t){this.log("detach: error closing socket:",t)}}return this.socket=null,this.active=!1,this.messageBuffer=Buffer.alloc(0),this.log("detach: handler cleaned up"),this}get isAttached(){return this.socket!==null}async handleData(e){if(!this.socket||!this.active)return this.log("handleData: no active socket, ignoring data"),0;this.log(`handleData: received ${e.length} bytes`),this.messageBuffer=Buffer.concat([this.messageBuffer,e]),this.inspectData("incoming",e);try{let t=0;for(;this.messageBuffer.length>0;){let i=0,r=!1;if(this.messageBuffer.length>=4){let n=this.messageBuffer.readInt32BE(0);if(this.messageBuffer.length>=8){let a=this.messageBuffer.readInt32BE(4);(a===196608||a===196608)&&(i=n,r=this.messageBuffer.length>=i)}!r&&this.messageBuffer.length>=5&&(i=1+this.messageBuffer.readInt32BE(1),r=this.messageBuffer.length>=i)}if(!r||i===0){this.log(`handleData: incomplete message, buffering ${this.messageBuffer.length} bytes`);break}let o=this.messageBuffer.slice(0,i);if(this.messageBuffer=this.messageBuffer.slice(i),this.log(`handleData: processing message of ${o.length} bytes`),!this.active||!this.socket){this.log("handleData: socket no longer active, stopping processing");break}let h=await this.queryQueue.enqueue(this.id,new Uint8Array(o));this.log(`handleData: received ${h.length} bytes from PGlite`),this.inspectData("outgoing",h),h.length>0&&this.socket&&this.socket.writable&&this.active&&await new Promise((n,a)=>{this.log("handleData: writing response to socket"),this.socket?.writable?this.socket.write(Buffer.from(h),c=>{c?(this.log("handleData: error writing to socket:",c),a(c)):(this.log(`handleData: socket sent: ${h.length} bytes`),n(h.length))}):(this.log("handleData: socket no longer writable"),n(0))}).catch(n=>{throw this.log("handleData: failed to write to socket:",n),n}),t+=h.length}return this.dispatchEvent(new CustomEvent("data",{detail:{incoming:e.length,outgoing:t}})),t}catch(t){throw this.log("handleData: error processing data:",t),t}}handleError(e){if(!this.active){this.log("handleError: handler not active, ignoring error");return}e.message?.includes("ECONNRESET")?this.log("handleError: client disconnected (ECONNRESET) - normal behavior"):e.message?.includes("Idle timeout")?this.log("handleError: connection idle timeout"):this.log("handleError:",e),this.active=!1,this.dispatchEvent(new CustomEvent("error",{detail:e})),this.detach(!0)}handleClose(){this.log("handleClose: socket closed"),this.active=!1,this.dispatchEvent(new CustomEvent("close")),this.detach(!1)}inspectData(e,t){if(this.inspect){console.log("-".repeat(75)),console.log(e==="incoming"?"-> incoming":"<- outgoing",t.length,"bytes");for(let i=0;i<t.length;i+=16){let r=Math.min(16,t.length-i),o="";for(let n=0;n<16;n++)if(n<r){let a=t[i+n];o+=a.toString(16).padStart(2,"0")+" "}else o+=" ";let h="";for(let n=0;n<r;n++){let a=t[i+n];h+=a>=32&&a<=126?String.fromCharCode(a):"."}console.log(`${i.toString(16).padStart(8,"0")} ${o} ${h}`)}}}};l.nextHandlerId=1;var u=l,g=class extends EventTarget{constructor(e){super();this.server=null;this.active=!1;this.handlers=new Set;this.db=e.db,e.path?this.path=e.path:(typeof e.port=="number"?this.port=e.port??e.port:this.port=5432,this.host=e.host||"127.0.0.1"),this.inspect=e.inspect??!1,this.debug=e.debug??!1,this.idleTimeout=e.idleTimeout??0,this.maxConnections=e.maxConnections??1,this.queryQueue=new d(this.db,this.debug),this.log(`constructor: created server on ${this.getServerConn()}`),this.log(`constructor: max connections: ${this.maxConnections}`),this.idleTimeout>0&&this.log(`constructor: idle timeout: ${this.idleTimeout}ms`)}log(e,...t){this.debug&&console.log(`[PGLiteSocketServer] ${e}`,...t)}async start(){if(this.log(`start: starting server on ${this.getServerConn()}`),this.server)throw new Error("Socket server already started");return await this.db.waitReady,this.active=!0,this.server=f(e=>{setImmediate(()=>this.handleConnection(e))}),this.server.maxConnections=this.maxConnections,new Promise((e,t)=>{if(!this.server)return t(new Error("Server not initialized"));if(this.server.on("error",i=>{this.log("start: server error:",i),this.dispatchEvent(new CustomEvent("error",{detail:i})),this.active||t(i)}),this.path)this.server.listen(this.path,()=>{this.log(`start: server listening on ${this.getServerConn()}`),this.dispatchEvent(new CustomEvent("listening",{detail:{path:this.path}})),e()});else{let i=this.server;i.listen(this.port,this.host,()=>{let r=i.address();if(r===null||typeof r!="object")throw Error("Expected address info");this.port=r.port,this.log(`start: server listening on ${this.getServerConn()}`),this.dispatchEvent(new CustomEvent("listening",{detail:{port:this.port,host:this.host}})),e()})}})}getServerConn(){return this.path?this.path:`${this.host}:${this.port}`}async stop(){this.log("stop: stopping server"),this.active=!1,this.log(`stop: detaching ${this.handlers.size} handlers`);for(let e of this.handlers)e.detach(!0);return this.handlers.clear(),this.server?new Promise(e=>{if(!this.server)return e();this.server.close(()=>{this.log("stop: server closed"),this.server=null,this.dispatchEvent(new CustomEvent("close")),e()})}):(this.log("stop: server not running, nothing to do"),Promise.resolve())}async handleConnection(e){let t={clientAddress:e.remoteAddress||"unknown",clientPort:e.remotePort||0};if(this.log(`handleConnection: new connection from ${t.clientAddress}:${t.clientPort}`),this.log(`handleConnection: active connections: ${this.handlers.size}, queued queries: ${this.queryQueue.getQueueLength()}`),!this.active){this.log("handleConnection: server not active, closing connection");try{e.end()}catch(r){this.log("handleConnection: error closing socket:",r)}return}if(this.handlers.size>=this.maxConnections){this.log("handleConnection: max connections reached, rejecting"),e.write(Buffer.from(`Too many connections
`)),e.end();return}let i=new u({queryQueue:this.queryQueue,closeOnDetach:!0,inspect:this.inspect,debug:this.debug,idleTimeout:this.idleTimeout});this.handlers.add(i),i.addEventListener("error",r=>{let o=r.detail;o?.message?.includes("ECONNRESET")?this.log(`handler #${i.handlerId}: client disconnected (ECONNRESET)`):o?.message?.includes("Idle timeout")?this.log(`handler #${i.handlerId}: idle timeout`):this.log(`handler #${i.handlerId}: error:`,o)}),i.addEventListener("close",()=>{this.log(`handler #${i.handlerId}: closed`),this.handlers.delete(i),this.log(`handleConnection: active connections: ${this.handlers.size}`)});try{await i.attach(e),this.dispatchEvent(new CustomEvent("connection",{detail:t}))}catch(r){this.log("handleConnection: error attaching socket:",r),this.handlers.delete(i),this.dispatchEvent(new CustomEvent("error",{detail:r}));try{e.end()}catch(o){this.log("handleConnection: error closing socket:",o)}}}getStats(){return{activeConnections:this.handlers.size,queuedQueries:this.queryQueue.getQueueLength(),maxConnections:this.maxConnections}}};export{y as a,u as b,g as c};
//# sourceMappingURL=chunk-JGAU6COP.js.map
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { PGlite } from '@electric-sql/pglite'\nimport { type Server, type Socket, createServer } from 'net'\n\n// Connection queue timeout in milliseconds\nexport const CONNECTION_QUEUE_TIMEOUT = 60000 // 60 seconds\n\n/**\n * Represents a queued query waiting for PGlite access\n */\ninterface QueuedQuery {\n handlerId: number\n message: Uint8Array\n resolve: (result: Uint8Array) => void\n reject: (error: Error) => void\n timestamp: number\n}\n\n/**\n * Global query queue manager\n * Ensures only one query executes at a time in PGlite\n */\nclass QueryQueueManager {\n private queue: QueuedQuery[] = []\n private processing = false\n private db: PGlite\n private debug: boolean\n private lastHandlerId: null | number = null\n\n constructor(db: PGlite, debug = false) {\n this.db = db\n this.debug = debug\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[QueryQueueManager] ${message}`, ...args)\n }\n }\n\n async enqueue(handlerId: number, message: Uint8Array): Promise<Uint8Array> {\n return new Promise((resolve, reject) => {\n const query: QueuedQuery = {\n handlerId,\n message,\n resolve,\n reject,\n timestamp: Date.now(),\n }\n\n this.queue.push(query)\n this.log(\n `enqueued query from handler #${handlerId}, queue size: ${this.queue.length}`,\n )\n\n // Process queue if not already processing\n if (!this.processing) {\n this.processQueue()\n }\n })\n }\n\n private async processQueue(): Promise<void> {\n if (this.processing || this.queue.length === 0) {\n return\n }\n\n this.processing = true\n\n while (this.queue.length > 0) {\n let query\n\n if (this.db.isInTransaction() && this.lastHandlerId) {\n const i = this.queue.findIndex(\n (q) => q.handlerId === this.lastHandlerId,\n )\n if (i === -1) {\n // we didn't find any other query from the same client!\n this.log(\n `transaction started, but no query from the same handler id found in queue`,\n this.lastHandlerId,\n )\n query = null\n } else {\n query = this.queue.splice(i, 1)[0]\n }\n } else {\n query = this.queue.shift()\n }\n if (!query) break\n\n const waitTime = Date.now() - query.timestamp\n this.log(\n `processing query from handler #${query.handlerId} (waited ${waitTime}ms)`,\n )\n\n try {\n // Execute the query with exclusive access to PGlite\n const result = await this.db.runExclusive(async () => {\n return await this.db.execProtocolRaw(query.message)\n })\n\n this.log(\n `query from handler #${query.handlerId} completed, ${result.length} bytes`,\n )\n this.lastHandlerId = query.handlerId\n query.resolve(result)\n } catch (error) {\n this.log(`query from handler #${query.handlerId} failed:`, error)\n query.reject(error as Error)\n }\n }\n\n this.processing = false\n this.log(`queue processing complete, queue length is`, this.queue.length)\n }\n\n getQueueLength(): number {\n return this.queue.length\n }\n\n clearQueueForHandler(handlerId: number): void {\n const before = this.queue.length\n this.queue = this.queue.filter((q) => {\n if (q.handlerId === handlerId) {\n q.reject(new Error('Handler disconnected'))\n return false\n }\n return true\n })\n const removed = before - this.queue.length\n if (removed > 0) {\n this.log(`cleared ${removed} queries for handler #${handlerId}`)\n }\n }\n\n async clearTransactionIfNeeded(handlerId: number): Promise<void> {\n if (this.db.isInTransaction() && this.lastHandlerId === handlerId) {\n await this.db.exec('ROLLBACK')\n this.lastHandlerId = null\n await this.processQueue()\n }\n }\n}\n\n/**\n * Options for creating a PGLiteSocketHandler\n */\nexport interface PGLiteSocketHandlerOptions {\n /** The query queue manager */\n queryQueue: QueryQueueManager\n /** Whether to close the socket when detached (default: false) */\n closeOnDetach?: boolean\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n /** Idle timeout in ms (0 to disable, default: 0) */\n idleTimeout?: number\n}\n\n/**\n * Handler for a single socket connection to PGlite\n * Each connection can remain open and send multiple queries\n */\nexport class PGLiteSocketHandler extends EventTarget {\n private queryQueue: QueryQueueManager\n private socket: Socket | null = null\n private active = false\n private closeOnDetach: boolean\n private inspect: boolean\n private debug: boolean\n private readonly id: number\n private messageBuffer: Buffer = Buffer.alloc(0)\n private idleTimer?: NodeJS.Timeout\n private idleTimeout: number\n private lastActivityTime: number = Date.now()\n\n // Static counter for generating unique handler IDs\n private static nextHandlerId = 1\n\n constructor(options: PGLiteSocketHandlerOptions) {\n super()\n this.queryQueue = options.queryQueue\n this.closeOnDetach = options.closeOnDetach ?? false\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.idleTimeout = options.idleTimeout ?? 0\n this.id = PGLiteSocketHandler.nextHandlerId++\n\n this.log('constructor: created new handler')\n }\n\n public get handlerId(): number {\n return this.id\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketHandler#${this.id}] ${message}`, ...args)\n }\n }\n\n public async attach(socket: Socket): Promise<PGLiteSocketHandler> {\n this.log(\n `attach: attaching socket from ${socket.remoteAddress}:${socket.remotePort}`,\n )\n\n if (this.socket) {\n throw new Error('Socket already attached')\n }\n\n this.socket = socket\n this.active = true\n this.lastActivityTime = Date.now()\n\n // Set up socket options\n socket.setNoDelay(true)\n\n // Set up idle timeout if configured\n if (this.idleTimeout > 0) {\n this.resetIdleTimer()\n }\n\n // Setup event handlers\n this.log(`attach: setting up socket event handlers`)\n\n socket.on('data', (data) => {\n this.lastActivityTime = Date.now()\n this.resetIdleTimer()\n\n setImmediate(async () => {\n try {\n await this.handleData(data)\n } catch (err) {\n this.log('socket on data error: ', err)\n this.handleError(err as Error)\n }\n })\n })\n\n socket.on('error', (err) => {\n setImmediate(() => this.handleError(err))\n })\n\n socket.on('close', () => {\n setImmediate(() => this.handleClose())\n })\n\n this.log(`attach: socket handler ready`)\n return this\n }\n\n private resetIdleTimer(): void {\n if (this.idleTimeout <= 0) return\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n }\n\n this.idleTimer = setTimeout(() => {\n const idleTime = Date.now() - this.lastActivityTime\n this.log(`idle timeout after ${idleTime}ms`)\n this.handleError(new Error('Idle timeout'))\n }, this.idleTimeout)\n }\n\n public async detach(close?: boolean): Promise<PGLiteSocketHandler> {\n this.log(`detach: detaching socket, close=${close ?? this.closeOnDetach}`)\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n this.idleTimer = undefined\n }\n\n // Clear any pending queries for this handler\n this.queryQueue.clearQueueForHandler(this.id)\n\n await this.queryQueue.clearTransactionIfNeeded(this.id)\n\n if (!this.socket) {\n this.log(`detach: no socket attached, nothing to do`)\n return this\n }\n\n // Remove all listeners\n this.socket.removeAllListeners('data')\n this.socket.removeAllListeners('error')\n this.socket.removeAllListeners('close')\n\n // Close the socket if requested\n if (close ?? this.closeOnDetach) {\n if (this.socket.writable) {\n this.log(`detach: closing socket`)\n try {\n this.socket.end()\n this.socket.destroy()\n } catch (err) {\n this.log(`detach: error closing socket:`, err)\n }\n }\n }\n\n this.socket = null\n this.active = false\n this.messageBuffer = Buffer.alloc(0)\n\n this.log(`detach: handler cleaned up`)\n return this\n }\n\n public get isAttached(): boolean {\n return this.socket !== null\n }\n\n private async handleData(data: Buffer): Promise<number> {\n if (!this.socket || !this.active) {\n this.log(`handleData: no active socket, ignoring data`)\n return 0\n }\n\n this.log(`handleData: received ${data.length} bytes`)\n\n // Append to buffer for message reassembly\n this.messageBuffer = Buffer.concat([this.messageBuffer, data])\n\n // Print the incoming data to the console\n this.inspectData('incoming', data)\n\n try {\n let totalProcessed = 0\n\n while (this.messageBuffer.length > 0) {\n // Determine message length\n let messageLength = 0\n let isComplete = false\n\n // Handle startup message (no type byte, just length)\n if (this.messageBuffer.length >= 4) {\n const firstInt = this.messageBuffer.readInt32BE(0)\n\n if (this.messageBuffer.length >= 8) {\n const secondInt = this.messageBuffer.readInt32BE(4)\n // PostgreSQL 3.0 protocol version\n if (secondInt === 196608 || secondInt === 0x00030000) {\n messageLength = firstInt\n isComplete = this.messageBuffer.length >= messageLength\n }\n }\n\n // Regular message (type byte + length)\n if (!isComplete && this.messageBuffer.length >= 5) {\n const msgLength = this.messageBuffer.readInt32BE(1)\n messageLength = 1 + msgLength\n isComplete = this.messageBuffer.length >= messageLength\n }\n }\n\n if (!isComplete || messageLength === 0) {\n this.log(\n `handleData: incomplete message, buffering ${this.messageBuffer.length} bytes`,\n )\n break\n }\n\n // Extract and process complete message\n const message = this.messageBuffer.slice(0, messageLength)\n this.messageBuffer = this.messageBuffer.slice(messageLength)\n\n this.log(`handleData: processing message of ${message.length} bytes`)\n\n // Check if socket is still active before processing\n if (!this.active || !this.socket) {\n this.log(`handleData: socket no longer active, stopping processing`)\n break\n }\n\n // Queue the query for execution\n // This allows multiple connections to queue queries simultaneously\n const result = await this.queryQueue.enqueue(\n this.id,\n new Uint8Array(message),\n )\n\n this.log(`handleData: received ${result.length} bytes from PGlite`)\n\n // Print the outgoing data to the console\n this.inspectData('outgoing', result)\n\n // Send response if available\n if (\n result.length > 0 &&\n this.socket &&\n this.socket.writable &&\n this.active\n ) {\n await new Promise<number>((resolve, reject) => {\n this.log(`handleData: writing response to socket`)\n if (this.socket?.writable) {\n this.socket.write(Buffer.from(result), (err?: any) => {\n if (err) {\n this.log(`handleData: error writing to socket:`, err)\n reject(err)\n } else {\n this.log(`handleData: socket sent: ${result.length} bytes`)\n resolve(result.length)\n }\n })\n } else {\n this.log(`handleData: socket no longer writable`)\n resolve(0)\n }\n }).catch((writeErr) => {\n this.log(`handleData: failed to write to socket:`, writeErr)\n throw writeErr\n })\n }\n\n totalProcessed += result.length\n }\n\n // Emit data event with byte sizes\n this.dispatchEvent(\n new CustomEvent('data', {\n detail: { incoming: data.length, outgoing: totalProcessed },\n }),\n )\n\n return totalProcessed\n } catch (err) {\n this.log(`handleData: error processing data:`, err)\n throw err\n }\n }\n\n private handleError(err: Error): void {\n if (!this.active) {\n this.log(`handleError: handler not active, ignoring error`)\n return\n }\n\n // ECONNRESET is expected behavior when clients disconnect\n if (err.message?.includes('ECONNRESET')) {\n this.log(\n `handleError: client disconnected (ECONNRESET) - normal behavior`,\n )\n } else if (err.message?.includes('Idle timeout')) {\n this.log(`handleError: connection idle timeout`)\n } else {\n this.log(`handleError:`, err)\n }\n\n this.active = false\n\n // Emit error event\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n\n // Clean up\n this.detach(true)\n }\n\n private handleClose(): void {\n this.log(`handleClose: socket closed`)\n this.active = false\n this.dispatchEvent(new CustomEvent('close'))\n this.detach(false)\n }\n\n private inspectData(\n direction: 'incoming' | 'outgoing',\n data: Buffer | Uint8Array,\n ): void {\n if (!this.inspect) return\n console.log('-'.repeat(75))\n if (direction === 'incoming') {\n console.log('-> incoming', data.length, 'bytes')\n } else {\n console.log('<- outgoing', data.length, 'bytes')\n }\n\n for (let offset = 0; offset < data.length; offset += 16) {\n const chunkSize = Math.min(16, data.length - offset)\n\n let hexPart = ''\n for (let i = 0; i < 16; i++) {\n if (i < chunkSize) {\n const byte = data[offset + i]\n hexPart += byte.toString(16).padStart(2, '0') + ' '\n } else {\n hexPart += ' '\n }\n }\n\n let asciiPart = ''\n for (let i = 0; i < chunkSize; i++) {\n const byte = data[offset + i]\n asciiPart += byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : '.'\n }\n\n console.log(\n `${offset.toString(16).padStart(8, '0')} ${hexPart} ${asciiPart}`,\n )\n }\n }\n}\n\n/**\n * Options for creating a PGLiteSocketServer\n */\nexport interface PGLiteSocketServerOptions {\n /** The PGlite database instance */\n db: PGlite\n /** The port to listen on (default: 5432) */\n port?: number\n /** The host to bind to (default: 127.0.0.1) */\n host?: string\n /** Unix socket path to bind to (default: undefined) */\n path?: string\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n /** Idle timeout in ms (0 to disable, default: 0) */\n idleTimeout?: number\n /** Maximum concurrent connections (default: 100) */\n maxConnections?: number\n}\n\n/**\n * PGLite Socket Server with support for multiple concurrent connections\n * Connections remain open and queries are queued at the query level\n */\nexport class PGLiteSocketServer extends EventTarget {\n readonly db: PGlite\n private server: Server | null = null\n private port?: number\n private host?: string\n private path?: string\n private active = false\n private inspect: boolean\n private debug: boolean\n private idleTimeout: number\n private maxConnections: number\n private handlers: Set<PGLiteSocketHandler> = new Set()\n private queryQueue: QueryQueueManager\n\n constructor(options: PGLiteSocketServerOptions) {\n super()\n this.db = options.db\n if (options.path) {\n this.path = options.path\n } else {\n if (typeof options.port === 'number') {\n // Keep port undefined on port 0, will be set by the OS when we start the server.\n this.port = options.port ?? options.port\n } else {\n this.port = 5432\n }\n this.host = options.host || '127.0.0.1'\n }\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.idleTimeout = options.idleTimeout ?? 0\n this.maxConnections = options.maxConnections ?? 1\n\n // Create the shared query queue\n this.queryQueue = new QueryQueueManager(this.db, this.debug)\n\n this.log(`constructor: created server on ${this.getServerConn()}`)\n this.log(`constructor: max connections: ${this.maxConnections}`)\n if (this.idleTimeout > 0) {\n this.log(`constructor: idle timeout: ${this.idleTimeout}ms`)\n }\n }\n\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketServer] ${message}`, ...args)\n }\n }\n\n public async start(): Promise<void> {\n this.log(`start: starting server on ${this.getServerConn()}`)\n\n if (this.server) {\n throw new Error('Socket server already started')\n }\n\n // Ensure PGlite is ready before accepting connections\n await this.db.waitReady\n\n this.active = true\n this.server = createServer((socket) => {\n setImmediate(() => this.handleConnection(socket))\n })\n\n this.server.maxConnections = this.maxConnections\n\n return new Promise<void>((resolve, reject) => {\n if (!this.server) return reject(new Error('Server not initialized'))\n\n this.server.on('error', (err) => {\n this.log(`start: server error:`, err)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n if (!this.active) {\n reject(err)\n }\n })\n\n if (this.path) {\n this.server.listen(this.path, () => {\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { path: this.path },\n }),\n )\n resolve()\n })\n } else {\n const server = this.server\n server.listen(this.port, this.host, () => {\n const address = server.address()\n // We are not using pipes, so return type should be AddressInfo\n if (address === null || typeof address !== 'object') {\n throw Error('Expected address info')\n }\n // Assign the new port number\n this.port = address.port\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { port: this.port, host: this.host },\n }),\n )\n resolve()\n })\n }\n })\n }\n\n public getServerConn(): string {\n if (this.path) return this.path\n return `${this.host}:${this.port}`\n }\n\n public async stop(): Promise<void> {\n this.log(`stop: stopping server`)\n\n this.active = false\n\n // Detach all handlers\n this.log(`stop: detaching ${this.handlers.size} handlers`)\n for (const handler of this.handlers) {\n handler.detach(true)\n }\n this.handlers.clear()\n\n if (!this.server) {\n this.log(`stop: server not running, nothing to do`)\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve) => {\n if (!this.server) return resolve()\n\n this.server.close(() => {\n this.log(`stop: server closed`)\n this.server = null\n this.dispatchEvent(new CustomEvent('close'))\n resolve()\n })\n })\n }\n\n private async handleConnection(socket: Socket): Promise<void> {\n const clientInfo = {\n clientAddress: socket.remoteAddress || 'unknown',\n clientPort: socket.remotePort || 0,\n }\n\n this.log(\n `handleConnection: new connection from ${clientInfo.clientAddress}:${clientInfo.clientPort}`,\n )\n this.log(\n `handleConnection: active connections: ${this.handlers.size}, queued queries: ${this.queryQueue.getQueueLength()}`,\n )\n\n if (!this.active) {\n this.log(`handleConnection: server not active, closing connection`)\n try {\n socket.end()\n } catch (err) {\n this.log(`handleConnection: error closing socket:`, err)\n }\n return\n }\n\n // Check connection limit\n if (this.handlers.size >= this.maxConnections) {\n this.log(`handleConnection: max connections reached, rejecting`)\n socket.write(Buffer.from('Too many connections\\n'))\n socket.end()\n return\n }\n\n // Create a new handler for this connection\n const handler = new PGLiteSocketHandler({\n queryQueue: this.queryQueue,\n closeOnDetach: true,\n inspect: this.inspect,\n debug: this.debug,\n idleTimeout: this.idleTimeout,\n })\n\n // Track this handler\n this.handlers.add(handler)\n\n // Handle errors\n handler.addEventListener('error', (event) => {\n const error = (event as CustomEvent<Error>).detail\n\n if (error?.message?.includes('ECONNRESET')) {\n this.log(\n `handler #${handler.handlerId}: client disconnected (ECONNRESET)`,\n )\n } else if (error?.message?.includes('Idle timeout')) {\n this.log(`handler #${handler.handlerId}: idle timeout`)\n } else {\n this.log(`handler #${handler.handlerId}: error:`, error)\n }\n })\n\n // Handle close event\n handler.addEventListener('close', () => {\n this.log(`handler #${handler.handlerId}: closed`)\n this.handlers.delete(handler)\n this.log(`handleConnection: active connections: ${this.handlers.size}`)\n })\n\n try {\n await handler.attach(socket)\n this.dispatchEvent(new CustomEvent('connection', { detail: clientInfo }))\n } catch (err) {\n this.log(`handleConnection: error attaching socket:`, err)\n this.handlers.delete(handler)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n try {\n socket.end()\n } catch (closeErr) {\n this.log(`handleConnection: error closing socket:`, closeErr)\n }\n }\n }\n\n public getStats() {\n return {\n activeConnections: this.handlers.size,\n queuedQueries: this.queryQueue.getQueueLength(),\n maxConnections: this.maxConnections,\n }\n }\n}\n"],"mappings":"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","names":["createServer","CONNECTION_QUEUE_TIMEOUT","QueryQueueManager","db","debug","message","args","handlerId","resolve","reject","query","i","q","waitTime","result","error","before","removed","_PGLiteSocketHandler","options","socket","data","err","idleTime","close","totalProcessed","messageLength","isComplete","firstInt","secondInt","writeErr","direction","offset","chunkSize","hexPart","byte","asciiPart","PGLiteSocketHandler","PGLiteSocketServer","server","address","handler","clientInfo","event","closeErr"]}