@electric-sql/pglite-socket
Version:
A socket implementation for PGlite enabling remote connections
16 lines (15 loc) • 5.26 kB
JavaScript
import{c as d}from"../chunk-ZWGLOPFM.js";import{PGlite as h}from"@electric-sql/pglite";import{parseArgs as u}from"node:util";import{spawn as p}from"node:child_process";var o=u({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)"},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)"},help:{type:"boolean",short:"?",default:!1,help:"Show help"}}}),g=`PGlite Socket Server
Usage: pglite-server [options]
Options:
-d, --db=PATH Database path (default: memory://)
-p, --port=PORT Port to listen on (default: 5432)
-h, --host=HOST Host to bind to (default: 127.0.0.1)
-u, --path=UNIX Unix socket to bind to (default: undefined). Takes precedence over host:port
-v, --debug=LEVEL Debug level 0-5 (default: 0)
-r, --run=COMMAND Command to run after server starts
--include-database-url Include DATABASE_URL in subprocess environment
--shutdown-timeout=MS Timeout for graceful subprocess shutdown in ms (default: 5000)
`,a=class{constructor(e){this.db=null;this.server=null;this.subprocessManager=null;this.config=e}static parseConfig(){return{dbPath:o.values.db,port:parseInt(o.values.port,10),host:o.values.host,path:o.values.path,debugLevel:parseInt(o.values.debug,10),runCommand:o.values.run,includeDatabaseUrl:o.values["include-database-url"],shutdownTimeout:parseInt(o.values["shutdown-timeout"],10)}}createDatabaseUrl(){let{host:e,port:t,path:s}=this.config;if(s){let n=s.endsWith("/.s.PGSQL.5432")?s.slice(0,-13):s;return`postgresql://postgres:postgres@/postgres?host=${encodeURIComponent(n)}`}else return`postgresql://postgres:postgres@${e}:${t}/postgres`}async initializeDatabase(){console.log(`Initializing PGLite with database: ${this.config.dbPath}`),console.log(`Debug level: ${this.config.debugLevel}`),this.db=new h(this.config.dbPath,{debug:this.config.debugLevel}),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 t=e.detail;if(console.log(`PGLiteSocketServer listening on ${JSON.stringify(t)}`),this.config.runCommand&&this.subprocessManager){let s=this.createDatabaseUrl();this.subprocessManager.spawn(this.config.runCommand,s,this.config.includeDatabaseUrl)}}),this.server.addEventListener("connection",e=>{let{clientAddress:t,clientPort:s}=e.detail;console.log(`Client connected from ${t}:${s}`)}),this.server.addEventListener("error",e=>{let t=e.detail;console.error("Socket server error:",t)})}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}),this.subprocessManager=new l(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)}},l=class{constructor(e){this.childProcess=null;this.onExit=e}get process(){return this.childProcess}spawn(e,t,s){console.log(`Running command: ${e}`);let n={...process.env};s&&(n.DATABASE_URL=t,console.log(`Setting DATABASE_URL=${t}`));let c=e.trim().split(/\s+/);this.childProcess=p(c[0],c.slice(1),{env:n,stdio:"inherit"}),this.childProcess.on("error",r=>{console.error("Error running command:",r),console.log("Subprocess failed to start, shutting down..."),this.onExit(1)}),this.childProcess.on("close",r=>{console.log(`Command exited with code ${r}`),this.childProcess=null,r!==null&&r!==0&&(console.log(`Child process failed with exit code ${r}, shutting down...`),this.onExit(r))})}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 v(){o.values.help&&(console.log(g),process.exit(0));try{let i=a.parseConfig();await new a(i).start()}catch(i){console.error("Unhandled error:",i),process.exit(1)}}v();
//# sourceMappingURL=server.js.map