first commit

This commit is contained in:
Ichitux
2026-04-05 03:08:53 +02:00
commit 1082d36c12
28015 changed files with 3767672 additions and 0 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,118 @@
import { PGlite } from '@electric-sql/pglite';
import { Socket } from 'net';
declare const CONNECTION_QUEUE_TIMEOUT = 60000;
/**
* Global query queue manager
* Ensures only one query executes at a time in PGlite
*/
declare class QueryQueueManager {
private queue;
private processing;
private db;
private debug;
private lastHandlerId;
constructor(db: PGlite, debug?: boolean);
private log;
enqueue(handlerId: number, message: Uint8Array, onData: (data: Uint8Array) => void): Promise<number>;
private processQueue;
getQueueLength(): number;
clearQueueForHandler(handlerId: number): void;
clearTransactionIfNeeded(handlerId: number): Promise<void>;
}
/**
* Options for creating a PGLiteSocketHandler
*/
interface PGLiteSocketHandlerOptions {
/** The query queue manager */
queryQueue: QueryQueueManager;
/** Whether to close the socket when detached (default: false) */
closeOnDetach?: boolean;
/** Print the incoming and outgoing data to the console in hex and ascii */
inspect?: boolean;
/** Enable debug logging of method calls */
debug?: boolean;
/** Idle timeout in ms (0 to disable, default: 0) */
idleTimeout?: number;
}
/**
* Handler for a single socket connection to PGlite
* Each connection can remain open and send multiple queries
*/
declare class PGLiteSocketHandler extends EventTarget {
private queryQueue;
private socket;
private active;
private closeOnDetach;
private inspect;
private debug;
private readonly id;
private messageBuffer;
private idleTimer?;
private idleTimeout;
private lastActivityTime;
private static nextHandlerId;
constructor(options: PGLiteSocketHandlerOptions);
get handlerId(): number;
private log;
attach(socket: Socket): Promise<PGLiteSocketHandler>;
private resetIdleTimer;
detach(close?: boolean): Promise<PGLiteSocketHandler>;
get isAttached(): boolean;
private handleData;
private handleError;
private handleClose;
private inspectData;
}
/**
* Options for creating a PGLiteSocketServer
*/
interface PGLiteSocketServerOptions {
/** The PGlite database instance */
db: PGlite;
/** The port to listen on (default: 5432) */
port?: number;
/** The host to bind to (default: 127.0.0.1) */
host?: string;
/** Unix socket path to bind to (default: undefined) */
path?: string;
/** Print the incoming and outgoing data to the console in hex and ascii */
inspect?: boolean;
/** Enable debug logging of method calls */
debug?: boolean;
/** Idle timeout in ms (0 to disable, default: 0) */
idleTimeout?: number;
/** Maximum concurrent connections (default: 100) */
maxConnections?: number;
}
/**
* PGLite Socket Server with support for multiple concurrent connections
* Connections remain open and queries are queued at the query level
*/
declare class PGLiteSocketServer extends EventTarget {
readonly db: PGlite;
private server;
private port?;
private host?;
private path?;
private active;
private inspect;
private debug;
private idleTimeout;
private maxConnections;
private handlers;
private queryQueue;
constructor(options: PGLiteSocketServerOptions);
private log;
start(): Promise<void>;
getServerConn(): string;
stop(): Promise<void>;
private handleConnection;
getStats(): {
activeConnections: number;
queuedQueries: number;
maxConnections: number;
};
}
export { CONNECTION_QUEUE_TIMEOUT, PGLiteSocketHandler, type PGLiteSocketHandlerOptions, PGLiteSocketServer, type PGLiteSocketServerOptions };

View File

@@ -0,0 +1,118 @@
import { PGlite } from '@electric-sql/pglite';
import { Socket } from 'net';
declare const CONNECTION_QUEUE_TIMEOUT = 60000;
/**
* Global query queue manager
* Ensures only one query executes at a time in PGlite
*/
declare class QueryQueueManager {
private queue;
private processing;
private db;
private debug;
private lastHandlerId;
constructor(db: PGlite, debug?: boolean);
private log;
enqueue(handlerId: number, message: Uint8Array, onData: (data: Uint8Array) => void): Promise<number>;
private processQueue;
getQueueLength(): number;
clearQueueForHandler(handlerId: number): void;
clearTransactionIfNeeded(handlerId: number): Promise<void>;
}
/**
* Options for creating a PGLiteSocketHandler
*/
interface PGLiteSocketHandlerOptions {
/** The query queue manager */
queryQueue: QueryQueueManager;
/** Whether to close the socket when detached (default: false) */
closeOnDetach?: boolean;
/** Print the incoming and outgoing data to the console in hex and ascii */
inspect?: boolean;
/** Enable debug logging of method calls */
debug?: boolean;
/** Idle timeout in ms (0 to disable, default: 0) */
idleTimeout?: number;
}
/**
* Handler for a single socket connection to PGlite
* Each connection can remain open and send multiple queries
*/
declare class PGLiteSocketHandler extends EventTarget {
private queryQueue;
private socket;
private active;
private closeOnDetach;
private inspect;
private debug;
private readonly id;
private messageBuffer;
private idleTimer?;
private idleTimeout;
private lastActivityTime;
private static nextHandlerId;
constructor(options: PGLiteSocketHandlerOptions);
get handlerId(): number;
private log;
attach(socket: Socket): Promise<PGLiteSocketHandler>;
private resetIdleTimer;
detach(close?: boolean): Promise<PGLiteSocketHandler>;
get isAttached(): boolean;
private handleData;
private handleError;
private handleClose;
private inspectData;
}
/**
* Options for creating a PGLiteSocketServer
*/
interface PGLiteSocketServerOptions {
/** The PGlite database instance */
db: PGlite;
/** The port to listen on (default: 5432) */
port?: number;
/** The host to bind to (default: 127.0.0.1) */
host?: string;
/** Unix socket path to bind to (default: undefined) */
path?: string;
/** Print the incoming and outgoing data to the console in hex and ascii */
inspect?: boolean;
/** Enable debug logging of method calls */
debug?: boolean;
/** Idle timeout in ms (0 to disable, default: 0) */
idleTimeout?: number;
/** Maximum concurrent connections (default: 100) */
maxConnections?: number;
}
/**
* PGLite Socket Server with support for multiple concurrent connections
* Connections remain open and queries are queued at the query level
*/
declare class PGLiteSocketServer extends EventTarget {
readonly db: PGlite;
private server;
private port?;
private host?;
private path?;
private active;
private inspect;
private debug;
private idleTimeout;
private maxConnections;
private handlers;
private queryQueue;
constructor(options: PGLiteSocketServerOptions);
private log;
start(): Promise<void>;
getServerConn(): string;
stop(): Promise<void>;
private handleConnection;
getStats(): {
activeConnections: number;
queuedQueries: number;
maxConnections: number;
};
}
export { CONNECTION_QUEUE_TIMEOUT, PGLiteSocketHandler, type PGLiteSocketHandlerOptions, PGLiteSocketServer, type PGLiteSocketServerOptions };

View File

@@ -0,0 +1,2 @@
import{a,b,c}from"./chunk-NSUMFCRM.js";export{a as CONNECTION_QUEUE_TIMEOUT,b as PGLiteSocketHandler,c as PGLiteSocketServer};
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
#!/usr/bin/env node

View File

@@ -0,0 +1 @@
#!/usr/bin/env node

View File

@@ -0,0 +1,20 @@
#!/usr/bin/env node
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]
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)
-e, --extensions=LIST Comma-separated list of extensions to load
Formats: vector, pgcrypto (built-in/contrib)
@org/package/path:exportedName (npm package)
-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)
-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","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

File diff suppressed because one or more lines are too long