postgres-memory-server 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/PostgresMemoryServer.ts","../src/errors.ts","../src/presets.ts"],"sourcesContent":["import process from \"node:process\";\n\nimport { PostgresMemoryServer } from \"./PostgresMemoryServer.js\";\nimport type {\n PostgresMemoryServerOptions,\n PostgresMemoryServerPreset,\n} from \"./types.js\";\n\nasync function main(): Promise<void> {\n const { options, initFiles, json } = parseArgs(process.argv.slice(2));\n\n const server = await PostgresMemoryServer.create(options);\n\n try {\n for (const file of initFiles) {\n await server.runSqlFile(file);\n }\n\n const payload = {\n uri: server.getUri(),\n host: server.getHost(),\n port: server.getPort(),\n database: server.getDatabase(),\n username: server.getUsername(),\n password: server.getPassword(),\n image: server.getImage(),\n };\n\n if (json) {\n process.stdout.write(`${JSON.stringify(payload, null, 2)}\\n`);\n } else {\n process.stdout.write(`POSTGRES_MEMORY_SERVER_URI=${payload.uri}\\n`);\n process.stdout.write(`POSTGRES_MEMORY_SERVER_HOST=${payload.host}\\n`);\n process.stdout.write(`POSTGRES_MEMORY_SERVER_PORT=${payload.port}\\n`);\n process.stdout.write(\n `POSTGRES_MEMORY_SERVER_DATABASE=${payload.database}\\n`,\n );\n process.stdout.write(\n `POSTGRES_MEMORY_SERVER_USERNAME=${payload.username}\\n`,\n );\n process.stdout.write(\n `POSTGRES_MEMORY_SERVER_PASSWORD=${payload.password}\\n`,\n );\n process.stdout.write(`POSTGRES_MEMORY_SERVER_IMAGE=${payload.image}\\n`);\n process.stdout.write(\"\\nPress Ctrl+C to stop the container.\\n\");\n }\n\n const stop = async () => {\n await server.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => {\n void stop();\n });\n process.on(\"SIGTERM\", () => {\n void stop();\n });\n\n await new Promise<void>(() => {\n // Intentionally never resolve. Signals will stop the process.\n });\n } catch (error) {\n await server.stop();\n throw error;\n }\n}\n\ntype ParsedArgs = {\n options: PostgresMemoryServerOptions;\n initFiles: string[];\n json: boolean;\n};\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const options: PostgresMemoryServerOptions = {};\n const initFiles: string[] = [];\n const extensions: string[] = [];\n let json = false;\n\n for (let index = 0; index < argv.length; index += 1) {\n const arg = argv[index];\n\n switch (arg) {\n case \"--preset\": {\n const value = readValue(\n argv,\n ++index,\n arg,\n ) as PostgresMemoryServerPreset;\n options.preset = value;\n break;\n }\n case \"--image\": {\n options.image = readValue(argv, ++index, arg);\n break;\n }\n case \"--version\": {\n options.version = readValue(argv, ++index, arg);\n break;\n }\n case \"--database\": {\n options.database = readValue(argv, ++index, arg);\n break;\n }\n case \"--username\": {\n options.username = readValue(argv, ++index, arg);\n break;\n }\n case \"--password\": {\n options.password = readValue(argv, ++index, arg);\n break;\n }\n case \"--extension\": {\n extensions.push(readValue(argv, ++index, arg));\n break;\n }\n case \"--init-file\": {\n initFiles.push(readValue(argv, ++index, arg));\n break;\n }\n case \"--json\": {\n json = true;\n break;\n }\n case \"--help\": {\n printHelp();\n process.exit(0);\n }\n default: {\n throw new Error(`Unknown argument: ${arg}`);\n }\n }\n }\n\n if (extensions.length > 0) {\n options.extensions = extensions;\n }\n\n return { options, initFiles, json };\n}\n\nfunction readValue(argv: string[], index: number, flag: string): string {\n const value = argv[index];\n if (!value) {\n throw new Error(`Missing value for ${flag}`);\n }\n return value;\n}\n\nfunction printHelp(): void {\n process.stdout.write(`postgres-memory-server\\n\\n`);\n process.stdout.write(`Options:\\n`);\n process.stdout.write(` --preset postgres|paradedb\\n`);\n process.stdout.write(` --version <tag>\\n`);\n process.stdout.write(` --image <image>\\n`);\n process.stdout.write(` --database <name>\\n`);\n process.stdout.write(` --username <name>\\n`);\n process.stdout.write(` --password <password>\\n`);\n process.stdout.write(` --extension <name> repeatable\\n`);\n process.stdout.write(` --init-file <path> repeatable\\n`);\n process.stdout.write(` --json\\n`);\n process.stdout.write(` --help\\n`);\n}\n\nvoid main().catch((error: unknown) => {\n const message =\n error instanceof Error ? (error.stack ?? error.message) : String(error);\n process.stderr.write(`${message}\\n`);\n process.exit(1);\n});\n","import { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { PostgreSqlContainer } from \"@testcontainers/postgresql\";\nimport { Client, type QueryResultRow } from \"pg\";\n\nimport { ServerStoppedError, SnapshotUnsupportedError } from \"./errors.js\";\nimport { buildInitStatements, normalizeOptions } from \"./presets.js\";\nimport type {\n PostgresConnectionOptions,\n PostgresMemoryServerOptions,\n QueryParams,\n QueryResponse,\n QueryText,\n} from \"./types.js\";\n\nexport type StartedPostgreSqlContainer = Awaited<\n ReturnType<PostgreSqlContainer[\"start\"]>\n>;\n\nexport class PostgresMemoryServer {\n private stopped = false;\n private readonly snapshotSupported: boolean;\n\n private constructor(\n private readonly container: StartedPostgreSqlContainer,\n private readonly options: ReturnType<typeof normalizeOptions>,\n ) {\n this.snapshotSupported = options.database !== \"postgres\";\n }\n\n static async create(\n options: PostgresMemoryServerOptions = {},\n ): Promise<PostgresMemoryServer> {\n const normalized = normalizeOptions(options);\n\n const container = await new PostgreSqlContainer(normalized.image)\n .withDatabase(normalized.database)\n .withUsername(normalized.username)\n .withPassword(normalized.password)\n .start();\n\n const server = new PostgresMemoryServer(container, normalized);\n\n const initStatements = buildInitStatements(normalized);\n if (initStatements.length > 0) {\n await server.runSql(initStatements);\n }\n\n return server;\n }\n\n static createPostgres(\n options: Omit<PostgresMemoryServerOptions, \"preset\"> = {},\n ): Promise<PostgresMemoryServer> {\n return PostgresMemoryServer.create({ ...options, preset: \"postgres\" });\n }\n\n static createParadeDb(\n options: Omit<PostgresMemoryServerOptions, \"preset\"> = {},\n ): Promise<PostgresMemoryServer> {\n return PostgresMemoryServer.create({ ...options, preset: \"paradedb\" });\n }\n\n getUri(): string {\n this.ensureRunning();\n return this.container.getConnectionUri();\n }\n\n getHost(): string {\n this.ensureRunning();\n return this.container.getHost();\n }\n\n getPort(): number {\n this.ensureRunning();\n return this.container.getPort();\n }\n\n getDatabase(): string {\n return this.options.database;\n }\n\n getUsername(): string {\n return this.options.username;\n }\n\n getPassword(): string {\n return this.options.password;\n }\n\n getImage(): string {\n return this.options.image;\n }\n\n getConnectionOptions(): PostgresConnectionOptions {\n return {\n host: this.getHost(),\n port: this.getPort(),\n database: this.getDatabase(),\n user: this.getUsername(),\n password: this.getPassword(),\n };\n }\n\n async query<Row extends QueryResultRow = QueryResultRow>(\n text: QueryText<Row>,\n params?: QueryParams,\n ): Promise<QueryResponse<Row>> {\n return this.withClient((client) => {\n if (typeof text === \"string\") {\n if (params === undefined) {\n return client.query<Row>(text);\n }\n\n return client.query<Row>(text, params);\n }\n\n return client.query<Row>(text);\n });\n }\n\n async withClient<T>(callback: (client: Client) => Promise<T>): Promise<T> {\n this.ensureRunning();\n\n const client = new Client({\n connectionString: this.getUri(),\n });\n\n await client.connect();\n try {\n return await callback(client);\n } finally {\n await client.end();\n }\n }\n\n async runSql(sql: string | string[]): Promise<void> {\n const statements = Array.isArray(sql) ? sql : [sql];\n\n await this.withClient(async (client) => {\n for (const statement of statements) {\n await client.query(statement);\n }\n });\n }\n\n async runSqlFile(filePath: string): Promise<void> {\n const sql = await fs.readFile(filePath, \"utf8\");\n await this.runSql(sql);\n }\n\n async runMigrationsDir(dirPath: string): Promise<string[]> {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n const files = entries\n .filter(\n (entry) => entry.isFile() && entry.name.toLowerCase().endsWith(\".sql\"),\n )\n .map((entry) => entry.name)\n .sort((left, right) => left.localeCompare(right));\n\n for (const file of files) {\n await this.runSqlFile(path.join(dirPath, file));\n }\n\n return files;\n }\n\n async snapshot(): Promise<void> {\n this.ensureRunning();\n this.ensureSnapshotSupported();\n await this.container.snapshot();\n }\n\n async restore(): Promise<void> {\n this.ensureRunning();\n this.ensureSnapshotSupported();\n await this.container.restoreSnapshot();\n }\n\n async stop(): Promise<void> {\n if (this.stopped) {\n return;\n }\n\n this.stopped = true;\n await this.container.stop();\n }\n\n private ensureRunning(): void {\n if (this.stopped) {\n throw new ServerStoppedError();\n }\n }\n\n private ensureSnapshotSupported(): void {\n if (!this.snapshotSupported) {\n throw new SnapshotUnsupportedError(this.options.database);\n }\n }\n}\n","export class PostgresMemoryServerError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n }\n}\n\nexport class SnapshotUnsupportedError extends PostgresMemoryServerError {\n constructor(database: string) {\n super(\n `Snapshots are not supported when the database name is \"${database}\". ` +\n `Use a non-system database name such as \"testdb\" before calling snapshot() or restore().`,\n );\n }\n}\n\nexport class ServerStoppedError extends PostgresMemoryServerError {\n constructor() {\n super(\"The PostgresMemoryServer has already been stopped.\");\n }\n}\n","import type {\n NormalizedPostgresMemoryServerOptions,\n PostgresMemoryServerOptions,\n PostgresMemoryServerPreset,\n} from \"./types.js\";\n\nexport const POSTGRES_IMAGE_REPOSITORY = \"postgres\";\nexport const PARADEDB_IMAGE_REPOSITORY = \"paradedb/paradedb\";\nexport const DEFAULT_POSTGRES_VERSION = \"17\";\nexport const DEFAULT_PARADEDB_VERSION = \"0.22.3-pg17\";\nexport const DEFAULT_POSTGRES_IMAGE = getImageForVersion(\n \"postgres\",\n DEFAULT_POSTGRES_VERSION,\n);\nexport const DEFAULT_PARADEDB_IMAGE = getImageForVersion(\n \"paradedb\",\n DEFAULT_PARADEDB_VERSION,\n);\n\nconst DEFAULT_DATABASE = \"testdb\";\nconst DEFAULT_USERNAME = \"testuser\";\nconst DEFAULT_PASSWORD = \"testpassword\";\n\nconst PARADEDB_DEFAULT_EXTENSIONS = [\"pg_search\", \"vector\"];\n\nexport function normalizeOptions(\n options: PostgresMemoryServerOptions = {},\n): NormalizedPostgresMemoryServerOptions {\n const preset = options.preset ?? \"postgres\";\n const version = options.version;\n const image = options.image ?? getImage(preset, version);\n const database = options.database ?? DEFAULT_DATABASE;\n const username = options.username ?? DEFAULT_USERNAME;\n const password = options.password ?? DEFAULT_PASSWORD;\n const extensions = options.extensions ?? getDefaultExtensions(preset);\n const initSql = options.initSql ?? [];\n\n return {\n preset,\n version,\n image,\n database,\n username,\n password,\n extensions,\n initSql,\n };\n}\n\nexport function getImageForVersion(\n preset: PostgresMemoryServerPreset,\n version: string,\n): string {\n const repository =\n preset === \"paradedb\"\n ? PARADEDB_IMAGE_REPOSITORY\n : POSTGRES_IMAGE_REPOSITORY;\n\n return `${repository}:${version}`;\n}\n\nexport function getDefaultImage(preset: PostgresMemoryServerPreset): string {\n return preset === \"paradedb\"\n ? DEFAULT_PARADEDB_IMAGE\n : DEFAULT_POSTGRES_IMAGE;\n}\n\nfunction getImage(\n preset: PostgresMemoryServerPreset,\n version?: string,\n): string {\n return version\n ? getImageForVersion(preset, version)\n : getDefaultImage(preset);\n}\n\nexport function getDefaultExtensions(\n preset: PostgresMemoryServerPreset,\n): string[] {\n return preset === \"paradedb\" ? [...PARADEDB_DEFAULT_EXTENSIONS] : [];\n}\n\nexport function buildInitStatements(\n options: NormalizedPostgresMemoryServerOptions,\n): string[] {\n const extensionStatements = options.extensions.map(\n (extension) =>\n `CREATE EXTENSION IF NOT EXISTS ${quoteIdentifier(extension)};`,\n );\n\n return [...extensionStatements, ...options.initSql];\n}\n\nfunction quoteIdentifier(name: string): string {\n if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n return name;\n }\n\n return `\"${name.replaceAll('\"', '\"\"')}\"`;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/PostgresMemoryServer.ts","../src/errors.ts","../src/native.ts","../src/presets.ts"],"sourcesContent":["import process from \"node:process\";\n\nimport { PostgresMemoryServer } from \"./PostgresMemoryServer.js\";\nimport type {\n PostgresMemoryServerOptions,\n PostgresMemoryServerPreset,\n} from \"./types.js\";\n\nasync function main(): Promise<void> {\n const { options, initFiles, json } = parseArgs(process.argv.slice(2));\n\n const server = await PostgresMemoryServer.create(options);\n\n try {\n for (const file of initFiles) {\n await server.runSqlFile(file);\n }\n\n const payload = {\n uri: server.getUri(),\n host: server.getHost(),\n port: server.getPort(),\n database: server.getDatabase(),\n username: server.getUsername(),\n password: server.getPassword(),\n image: server.getImage(),\n };\n\n if (json) {\n process.stdout.write(`${JSON.stringify(payload, null, 2)}\\n`);\n } else {\n process.stdout.write(`POSTGRES_MEMORY_SERVER_URI=${payload.uri}\\n`);\n process.stdout.write(`POSTGRES_MEMORY_SERVER_HOST=${payload.host}\\n`);\n process.stdout.write(`POSTGRES_MEMORY_SERVER_PORT=${payload.port}\\n`);\n process.stdout.write(\n `POSTGRES_MEMORY_SERVER_DATABASE=${payload.database}\\n`,\n );\n process.stdout.write(\n `POSTGRES_MEMORY_SERVER_USERNAME=${payload.username}\\n`,\n );\n process.stdout.write(\n `POSTGRES_MEMORY_SERVER_PASSWORD=${payload.password}\\n`,\n );\n process.stdout.write(`POSTGRES_MEMORY_SERVER_IMAGE=${payload.image}\\n`);\n process.stdout.write(\"\\nPress Ctrl+C to stop the server.\\n\");\n }\n\n const stop = async () => {\n await server.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => {\n void stop();\n });\n process.on(\"SIGTERM\", () => {\n void stop();\n });\n\n await new Promise<void>(() => {\n // Intentionally never resolve. Signals will stop the process.\n });\n } catch (error) {\n await server.stop().catch(() => {});\n throw error;\n }\n}\n\ntype ParsedArgs = {\n options: PostgresMemoryServerOptions;\n initFiles: string[];\n json: boolean;\n};\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const options: PostgresMemoryServerOptions = {};\n const initFiles: string[] = [];\n const extensions: string[] = [];\n let json = false;\n\n for (let index = 0; index < argv.length; index += 1) {\n const arg = argv[index];\n\n switch (arg) {\n case \"--preset\": {\n const value = readValue(\n argv,\n ++index,\n arg,\n ) as PostgresMemoryServerPreset;\n options.preset = value;\n break;\n }\n case \"--image\": {\n // Deprecated: Docker images are no longer used. Ignore silently.\n readValue(argv, ++index, arg);\n break;\n }\n case \"--version\": {\n options.version = readValue(argv, ++index, arg);\n break;\n }\n case \"--database\": {\n options.database = readValue(argv, ++index, arg);\n break;\n }\n case \"--username\": {\n options.username = readValue(argv, ++index, arg);\n break;\n }\n case \"--password\": {\n options.password = readValue(argv, ++index, arg);\n break;\n }\n case \"--extension\": {\n extensions.push(readValue(argv, ++index, arg));\n break;\n }\n case \"--init-file\": {\n initFiles.push(readValue(argv, ++index, arg));\n break;\n }\n case \"--json\": {\n json = true;\n break;\n }\n case \"--help\": {\n printHelp();\n process.exit(0);\n }\n default: {\n throw new Error(`Unknown argument: ${arg}`);\n }\n }\n }\n\n if (extensions.length > 0) {\n options.extensions = extensions;\n }\n\n return { options, initFiles, json };\n}\n\nfunction readValue(argv: string[], index: number, flag: string): string {\n const value = argv[index];\n if (!value) {\n throw new Error(`Missing value for ${flag}`);\n }\n return value;\n}\n\nfunction printHelp(): void {\n process.stdout.write(`postgres-memory-server\\n\\n`);\n process.stdout.write(`Options:\\n`);\n process.stdout.write(` --preset postgres|paradedb\\n`);\n process.stdout.write(` --version <tag>\\n`);\n process.stdout.write(` --image <image> (deprecated, ignored)\\n`);\n process.stdout.write(` --database <name>\\n`);\n process.stdout.write(` --username <name>\\n`);\n process.stdout.write(` --password <password>\\n`);\n process.stdout.write(` --extension <name> repeatable\\n`);\n process.stdout.write(` --init-file <path> repeatable\\n`);\n process.stdout.write(` --json\\n`);\n process.stdout.write(` --help\\n`);\n}\n\nvoid main().catch((error: unknown) => {\n const message =\n error instanceof Error ? (error.stack ?? error.message) : String(error);\n process.stderr.write(`${message}\\n`);\n process.exit(1);\n});\n","import { promises as fs, rmSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport process from \"node:process\";\n\nimport EmbeddedPostgres from \"embedded-postgres\";\nimport { Client, type QueryResultRow } from \"pg\";\n\nimport {\n ExtensionInstallError,\n ServerStoppedError,\n SnapshotUnsupportedError,\n} from \"./errors.js\";\nimport {\n buildInitStatements,\n normalizeOptions,\n resolveParadeDBVersion,\n DEFAULT_POSTGRES_VERSION,\n} from \"./presets.js\";\nimport {\n getFreePort,\n getNativeDir,\n installParadeDBExtension,\n installPgVectorExtension,\n sweepOrphanedDataDirs,\n} from \"./native.js\";\nimport type {\n PostgresConnectionOptions,\n PostgresMemoryServerOptions,\n QueryParams,\n QueryResponse,\n QueryText,\n} from \"./types.js\";\n\n// Track all live instances so we can clean up their dataDirs on process exit.\nconst liveInstances = new Set<PostgresMemoryServer>();\nlet exitHandlersRegistered = false;\nlet orphanSweepDone = false;\n\nfunction registerExitHandlers(): void {\n if (exitHandlersRegistered) return;\n exitHandlersRegistered = true;\n\n const cleanup = () => {\n for (const instance of liveInstances) {\n try {\n instance._cleanupSync();\n } catch {\n // best-effort\n }\n }\n };\n\n process.once(\"exit\", cleanup);\n\n // For SIGINT/SIGTERM/uncaughtException we run cleanup then re-raise so\n // we don't override existing handlers' decisions about whether to exit.\n const signalCleanup = (signal: NodeJS.Signals) => {\n cleanup();\n // Remove our handler so a re-raise of the signal terminates normally.\n process.removeListener(signal, signalCleanup);\n process.kill(process.pid, signal);\n };\n process.on(\"SIGINT\", signalCleanup);\n process.on(\"SIGTERM\", signalCleanup);\n process.on(\"SIGHUP\", signalCleanup);\n}\n\nexport class PostgresMemoryServer {\n private stopped = false;\n private readonly snapshotSupported: boolean;\n private hasSnapshot = false;\n\n private constructor(\n private readonly pg: EmbeddedPostgres,\n private readonly port: number,\n private readonly dataDir: string,\n private readonly options: ReturnType<typeof normalizeOptions>,\n ) {\n this.snapshotSupported = options.database !== \"postgres\";\n }\n\n static async create(\n options: PostgresMemoryServerOptions = {},\n ): Promise<PostgresMemoryServer> {\n // One-time sweep of orphaned data dirs from prior crashed runs.\n if (!orphanSweepDone) {\n orphanSweepDone = true;\n await sweepOrphanedDataDirs().catch(() => {\n // best-effort cleanup\n });\n }\n\n const normalized = normalizeOptions(options);\n const port = await getFreePort();\n const dataDir = await fs.mkdtemp(\n path.join(os.tmpdir(), \"postgres-memory-server-\"),\n );\n\n let pg: EmbeddedPostgres | undefined;\n\n try {\n const postgresFlags: string[] = [];\n\n // Install ParadeDB extension if needed\n if (normalized.preset === \"paradedb\") {\n const nativeDir = getNativeDir();\n const extVersion = resolveParadeDBVersion(normalized.version);\n const pgMajor = DEFAULT_POSTGRES_VERSION;\n\n try {\n await installParadeDBExtension(nativeDir, extVersion, pgMajor);\n } catch (error) {\n throw new ExtensionInstallError(\n \"pg_search\",\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n\n if (normalized.extensions.includes(\"vector\")) {\n try {\n await installPgVectorExtension(nativeDir, pgMajor);\n } catch (error) {\n throw new ExtensionInstallError(\n \"vector\",\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n\n if (\n normalized.extensions.includes(\"pg_search\") ||\n normalized.extensions.length === 0\n ) {\n postgresFlags.push(\"-c\", \"shared_preload_libraries=pg_search\");\n }\n }\n\n pg = new EmbeddedPostgres({\n databaseDir: dataDir,\n port,\n user: normalized.username,\n password: normalized.password,\n persistent: false,\n postgresFlags,\n onLog: () => {},\n onError: () => {},\n });\n\n await pg.initialise();\n await pg.start();\n\n if (normalized.database !== \"postgres\") {\n await pg.createDatabase(normalized.database);\n }\n\n const server = new PostgresMemoryServer(pg, port, dataDir, normalized);\n liveInstances.add(server);\n registerExitHandlers();\n\n const initStatements = buildInitStatements(normalized);\n if (initStatements.length > 0) {\n await server.runSql(initStatements);\n }\n\n return server;\n } catch (error) {\n // Cleanup on failure: stop any partial postgres process and rm dataDir.\n if (pg) {\n try {\n await pg.stop();\n } catch {\n // best-effort\n }\n }\n await fs\n .rm(dataDir, { recursive: true, force: true })\n .catch(() => {});\n throw error;\n }\n }\n\n static createPostgres(\n options: Omit<PostgresMemoryServerOptions, \"preset\"> = {},\n ): Promise<PostgresMemoryServer> {\n return PostgresMemoryServer.create({ ...options, preset: \"postgres\" });\n }\n\n static createParadeDb(\n options: Omit<PostgresMemoryServerOptions, \"preset\"> = {},\n ): Promise<PostgresMemoryServer> {\n return PostgresMemoryServer.create({ ...options, preset: \"paradedb\" });\n }\n\n getUri(): string {\n this.ensureRunning();\n return `postgres://${this.options.username}:${this.options.password}@localhost:${this.port}/${this.options.database}`;\n }\n\n getHost(): string {\n this.ensureRunning();\n return \"localhost\";\n }\n\n getPort(): number {\n this.ensureRunning();\n return this.port;\n }\n\n getDatabase(): string {\n return this.options.database;\n }\n\n getUsername(): string {\n return this.options.username;\n }\n\n getPassword(): string {\n return this.options.password;\n }\n\n getImage(): string {\n return this.options.image;\n }\n\n /**\n * Returns the absolute path to the temporary PostgreSQL data directory\n * for this instance. Useful for debugging or backing up state. The\n * directory is automatically removed by `stop()`.\n */\n getDataDir(): string {\n return this.dataDir;\n }\n\n getConnectionOptions(): PostgresConnectionOptions {\n return {\n host: this.getHost(),\n port: this.getPort(),\n database: this.getDatabase(),\n user: this.getUsername(),\n password: this.getPassword(),\n };\n }\n\n async query<Row extends QueryResultRow = QueryResultRow>(\n text: QueryText<Row>,\n params?: QueryParams,\n ): Promise<QueryResponse<Row>> {\n return this.withClient((client) => {\n if (typeof text === \"string\") {\n if (params === undefined) {\n return client.query<Row>(text);\n }\n\n return client.query<Row>(text, params);\n }\n\n return client.query<Row>(text);\n });\n }\n\n async withClient<T>(callback: (client: Client) => Promise<T>): Promise<T> {\n this.ensureRunning();\n\n const client = new Client({\n connectionString: this.getUri(),\n });\n\n await client.connect();\n try {\n return await callback(client);\n } finally {\n await client.end();\n }\n }\n\n async runSql(sql: string | string[]): Promise<void> {\n const statements = Array.isArray(sql) ? sql : [sql];\n\n await this.withClient(async (client) => {\n for (const statement of statements) {\n await client.query(statement);\n }\n });\n }\n\n async runSqlFile(filePath: string): Promise<void> {\n const sql = await fs.readFile(filePath, \"utf8\");\n await this.runSql(sql);\n }\n\n async runMigrationsDir(dirPath: string): Promise<string[]> {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n const files = entries\n .filter(\n (entry) => entry.isFile() && entry.name.toLowerCase().endsWith(\".sql\"),\n )\n .map((entry) => entry.name)\n .sort((left, right) => left.localeCompare(right));\n\n for (const file of files) {\n await this.runSqlFile(path.join(dirPath, file));\n }\n\n return files;\n }\n\n /**\n * Create a snapshot of the current database state.\n * Uses PostgreSQL template databases for fast, native snapshots.\n */\n async snapshot(): Promise<void> {\n this.ensureRunning();\n this.ensureSnapshotSupported();\n\n const snapshotDb = `${this.options.database}_snapshot`;\n\n await this.withAdminClient(async (client) => {\n // Terminate other connections to the database\n await client.query(\n `SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = $1 AND pid != pg_backend_pid()`,\n [this.options.database],\n );\n\n // Drop existing snapshot if any\n if (this.hasSnapshot) {\n await client.query(`DROP DATABASE IF EXISTS \"${snapshotDb}\"`);\n }\n\n // Create snapshot as a template copy\n await client.query(\n `CREATE DATABASE \"${snapshotDb}\" TEMPLATE \"${this.options.database}\"`,\n );\n });\n\n this.hasSnapshot = true;\n }\n\n /**\n * Restore the database to the last snapshot.\n * Drops and recreates the database from the snapshot template.\n */\n async restore(): Promise<void> {\n this.ensureRunning();\n this.ensureSnapshotSupported();\n\n if (!this.hasSnapshot) {\n throw new Error(\n \"No snapshot exists. Call snapshot() before calling restore().\",\n );\n }\n\n const snapshotDb = `${this.options.database}_snapshot`;\n\n await this.withAdminClient(async (client) => {\n // Terminate all connections to the target database\n await client.query(\n `SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = $1 AND pid != pg_backend_pid()`,\n [this.options.database],\n );\n\n // Drop and recreate from snapshot\n await client.query(`DROP DATABASE \"${this.options.database}\"`);\n await client.query(\n `CREATE DATABASE \"${this.options.database}\" TEMPLATE \"${snapshotDb}\"`,\n );\n });\n }\n\n async stop(): Promise<void> {\n if (this.stopped) {\n return;\n }\n\n this.stopped = true;\n liveInstances.delete(this);\n\n try {\n await this.pg.stop();\n } catch {\n // Even if pg.stop() fails (e.g., process never started, already dead),\n // we still want to remove the data directory below.\n }\n\n // Defensive cleanup. embedded-postgres only deletes the data dir when\n // its `process` field is set; if start() failed before that, the dir\n // would be leaked. force: true makes this a no-op if already gone.\n await fs\n .rm(this.dataDir, { recursive: true, force: true })\n .catch(() => {});\n }\n\n /**\n * Synchronous cleanup for use in process exit handlers. Cannot await,\n * so we just remove the data directory and let the OS reap the postgres\n * child process. embedded-postgres registers its own exit hook to kill\n * the process; this method is a backup for the data directory only.\n *\n * @internal\n */\n _cleanupSync(): void {\n if (this.stopped) {\n return;\n }\n this.stopped = true;\n liveInstances.delete(this);\n try {\n rmSync(this.dataDir, { recursive: true, force: true });\n } catch {\n // best-effort\n }\n }\n\n /**\n * Connect to the \"postgres\" system database for admin operations\n * (snapshot, restore, etc.).\n */\n private async withAdminClient<T>(\n callback: (client: Client) => Promise<T>,\n ): Promise<T> {\n const client = new Client({\n host: \"localhost\",\n port: this.port,\n database: \"postgres\",\n user: this.options.username,\n password: this.options.password,\n });\n\n await client.connect();\n try {\n return await callback(client);\n } finally {\n await client.end();\n }\n }\n\n private ensureRunning(): void {\n if (this.stopped) {\n throw new ServerStoppedError();\n }\n }\n\n private ensureSnapshotSupported(): void {\n if (!this.snapshotSupported) {\n throw new SnapshotUnsupportedError(this.options.database);\n }\n }\n}\n","export class PostgresMemoryServerError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n }\n}\n\nexport class SnapshotUnsupportedError extends PostgresMemoryServerError {\n constructor(database: string) {\n super(\n `Snapshots are not supported when the database name is \"${database}\". ` +\n `Use a non-system database name such as \"testdb\" before calling snapshot() or restore().`,\n );\n }\n}\n\nexport class ServerStoppedError extends PostgresMemoryServerError {\n constructor() {\n super(\"The PostgresMemoryServer has already been stopped.\");\n }\n}\n\nexport class ExtensionInstallError extends PostgresMemoryServerError {\n constructor(extensionName: string, cause?: Error) {\n super(\n `Failed to install the \"${extensionName}\" extension. ${cause?.message ?? \"\"}`.trim(),\n cause ? { cause } : undefined,\n );\n }\n}\n","import { promises as fs, readFileSync, existsSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { execFile as execFileCb } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport net from \"node:net\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst execFile = promisify(execFileCb);\n\n/**\n * Get a free TCP port by binding to port 0 and reading the assigned port.\n */\nexport async function getFreePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const server = net.createServer();\n server.listen(0, () => {\n const { port } = server.address() as net.AddressInfo;\n server.close(() => resolve(port));\n });\n server.on(\"error\", reject);\n });\n}\n\n/**\n * Get the PG major version from the installed embedded-postgres package.\n * The npm package version mirrors the PG version (e.g., 18.3.0-beta.16 = PG 18).\n */\nexport function getPgMajorVersion(): string {\n // Resolve the main entry of embedded-postgres, then walk up to find package.json\n const req = createRequire(import.meta.url);\n const mainEntry = req.resolve(\"embedded-postgres\");\n let dir = path.dirname(mainEntry);\n\n // Walk up until we find a package.json with name \"embedded-postgres\"\n while (dir !== path.dirname(dir)) {\n const candidate = path.join(dir, \"package.json\");\n try {\n const content = readFileSync(candidate, \"utf8\");\n const pkg = JSON.parse(content) as { name?: string; version?: string };\n if (pkg.name === \"embedded-postgres\" && pkg.version) {\n const major = pkg.version.split(\".\")[0];\n if (major) return major;\n }\n } catch {\n // continue walking up\n }\n dir = path.dirname(dir);\n }\n\n throw new Error(\n \"Could not determine embedded-postgres version. Ensure embedded-postgres is installed.\",\n );\n}\n\n/**\n * Get the native directory of the installed embedded-postgres platform package.\n * This directory contains bin/, lib/, and share/ subdirectories.\n */\nexport function getNativeDir(): string {\n const platform = os.platform();\n const arch = os.arch();\n\n const platformPkgNames: Record<string, Record<string, string>> = {\n darwin: {\n arm64: \"@embedded-postgres/darwin-arm64\",\n x64: \"@embedded-postgres/darwin-x64\",\n },\n linux: {\n x64: \"@embedded-postgres/linux-x64\",\n arm64: \"@embedded-postgres/linux-arm64\",\n },\n win32: {\n x64: \"@embedded-postgres/windows-x64\",\n },\n };\n\n const pkgName = platformPkgNames[platform]?.[arch];\n if (!pkgName) {\n throw new Error(`Unsupported platform: ${platform}-${arch}`);\n }\n\n const req = createRequire(import.meta.url);\n // Resolve the package's main entry, then find the native/ dir relative to it\n const mainEntry = req.resolve(pkgName);\n let dir = path.dirname(mainEntry);\n\n // Walk up to find the package root (containing native/)\n while (dir !== path.dirname(dir)) {\n const nativeDir = path.join(dir, \"native\");\n if (existsSync(nativeDir)) {\n return nativeDir;\n }\n dir = path.dirname(dir);\n }\n\n throw new Error(\n `Could not find native directory for ${pkgName}. Ensure embedded-postgres is installed correctly.`,\n );\n}\n\n/**\n * Get the cache directory for downloaded extension binaries.\n */\nexport function getCacheDir(): string {\n const xdgCache = process.env.XDG_CACHE_HOME;\n const base = xdgCache || path.join(os.homedir(), \".cache\");\n return path.join(base, \"postgres-memory-server\");\n}\n\n/**\n * Install the ParadeDB pg_search extension into the embedded-postgres native directory.\n * Downloads from GitHub releases if not already cached.\n */\nexport async function installParadeDBExtension(\n nativeDir: string,\n paradedbVersion: string,\n pgMajorVersion: string,\n): Promise<void> {\n // Check if already installed\n const libDir = path.join(nativeDir, \"lib\", \"postgresql\");\n const extDir = path.join(nativeDir, \"share\", \"postgresql\", \"extension\");\n\n const soName =\n os.platform() === \"darwin\" && parseInt(pgMajorVersion, 10) >= 16\n ? \"pg_search.dylib\"\n : \"pg_search.so\";\n\n try {\n await fs.access(path.join(libDir, soName));\n await fs.access(path.join(extDir, \"pg_search.control\"));\n return; // Already installed\n } catch {\n // Not installed, proceed\n }\n\n const cacheDir = getCacheDir();\n const platform = os.platform();\n const arch = os.arch();\n const cacheKey = `paradedb-${paradedbVersion}-pg${pgMajorVersion}-${platform}-${arch}`;\n const cachedDir = path.join(cacheDir, cacheKey);\n\n // Check cache\n let cached = false;\n try {\n await fs.access(path.join(cachedDir, \"lib\", soName));\n cached = true;\n } catch {\n // Not cached\n }\n\n if (!cached) {\n const url = buildDownloadUrl(\n paradedbVersion,\n pgMajorVersion,\n platform,\n arch,\n );\n const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), \"paradedb-\"));\n\n try {\n const filename = decodeURIComponent(url.split(\"/\").pop()!);\n const archivePath = path.join(tmpDir, filename);\n\n await downloadFile(url, archivePath);\n\n const extractedDir = path.join(tmpDir, \"extracted\");\n await fs.mkdir(extractedDir, { recursive: true });\n\n if (platform === \"darwin\") {\n await extractPkg(archivePath, extractedDir);\n } else {\n await extractDeb(archivePath, extractedDir);\n }\n\n // Cache the extracted extension files\n const cacheLibDir = path.join(cachedDir, \"lib\");\n const cacheExtDir = path.join(cachedDir, \"extension\");\n await fs.mkdir(cacheLibDir, { recursive: true });\n await fs.mkdir(cacheExtDir, { recursive: true });\n\n const soFiles = await findFiles(\n extractedDir,\n /pg_search\\.(so|dylib)$/,\n );\n for (const soFile of soFiles) {\n await copyFileWithPermissions(soFile, path.join(cacheLibDir, path.basename(soFile)));\n }\n\n const extFiles = await findFiles(\n extractedDir,\n /pg_search[^/]*(\\.control|\\.sql)$/,\n );\n for (const extFile of extFiles) {\n await copyFileWithPermissions(\n extFile,\n path.join(cacheExtDir, path.basename(extFile)),\n );\n }\n } finally {\n await fs.rm(tmpDir, { recursive: true, force: true });\n }\n }\n\n // Copy from cache to native dir\n await fs.mkdir(libDir, { recursive: true });\n await fs.mkdir(extDir, { recursive: true });\n\n const cacheLibDir = path.join(cachedDir, \"lib\");\n const cacheExtDir = path.join(cachedDir, \"extension\");\n\n for (const file of await fs.readdir(cacheLibDir)) {\n await copyFileWithPermissions(path.join(cacheLibDir, file), path.join(libDir, file));\n }\n\n for (const file of await fs.readdir(cacheExtDir)) {\n await copyFileWithPermissions(path.join(cacheExtDir, file), path.join(extDir, file));\n }\n}\n\nfunction buildDownloadUrl(\n version: string,\n pgMajorVersion: string,\n platform: string,\n arch: string,\n): string {\n const base = `https://github.com/paradedb/paradedb/releases/download/v${version}`;\n\n if (platform === \"darwin\") {\n if (arch !== \"arm64\") {\n throw new Error(\n \"ParadeDB only provides macOS binaries for arm64 (Apple Silicon). Intel Macs are not supported.\",\n );\n }\n const macosName = getMacOSCodename();\n return `${base}/pg_search%40${pgMajorVersion}--${version}.arm64_${macosName}.pkg`;\n }\n\n if (platform === \"linux\") {\n const debArch = arch === \"arm64\" ? \"arm64\" : \"amd64\";\n return `${base}/postgresql-${pgMajorVersion}-pg-search_${version}-1PARADEDB-bookworm_${debArch}.deb`;\n }\n\n throw new Error(\n `ParadeDB does not provide prebuilt binaries for ${platform}. Use the Docker-based preset instead.`,\n );\n}\n\nfunction getMacOSCodename(): string {\n const release = os.release();\n const majorVersion = parseInt(release.split(\".\")[0] ?? \"0\", 10);\n\n if (majorVersion >= 24) return \"sequoia\";\n if (majorVersion >= 23) return \"sonoma\";\n throw new Error(\n `ParadeDB requires macOS 14 (Sonoma) or later. Detected Darwin ${release}.`,\n );\n}\n\nasync function downloadFile(url: string, destPath: string): Promise<void> {\n const response = await fetch(url, { redirect: \"follow\" });\n\n if (!response.ok) {\n throw new Error(\n `Failed to download ParadeDB extension from ${url}: ${response.status} ${response.statusText}`,\n );\n }\n\n const buffer = Buffer.from(await response.arrayBuffer());\n await fs.writeFile(destPath, buffer);\n}\n\nasync function extractDeb(\n debPath: string,\n extractDir: string,\n): Promise<void> {\n await execFile(\"ar\", [\"x\", debPath], { cwd: extractDir });\n\n const files = await fs.readdir(extractDir);\n const dataTar = files.find((f) => f.startsWith(\"data.tar\"));\n\n if (!dataTar) {\n throw new Error(\n \"No data.tar.* found in .deb archive. The ParadeDB package format may have changed.\",\n );\n }\n\n const dataDir = path.join(extractDir, \"data\");\n await fs.mkdir(dataDir, { recursive: true });\n await execFile(\"tar\", [\n \"xf\",\n path.join(extractDir, dataTar),\n \"-C\",\n dataDir,\n ]);\n}\n\nasync function extractPkg(\n pkgPath: string,\n extractDir: string,\n): Promise<void> {\n const pkgDir = path.join(extractDir, \"pkg\");\n await execFile(\"pkgutil\", [\"--expand-full\", pkgPath, pkgDir]);\n}\n\n/**\n * Copy a file by reading and writing its contents, avoiding EACCES errors\n * when the source file is read-only (e.g., extracted from tar archives).\n */\nasync function copyFileWithPermissions(\n src: string,\n dest: string,\n): Promise<void> {\n const content = await fs.readFile(src);\n await fs.writeFile(dest, content, { mode: 0o755 });\n}\n\nasync function findFiles(dir: string, pattern: RegExp): Promise<string[]> {\n const results: string[] = [];\n\n async function walk(currentDir: string): Promise<void> {\n const entries = await fs.readdir(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n if (entry.isDirectory()) {\n await walk(fullPath);\n } else if (pattern.test(entry.name)) {\n results.push(fullPath);\n }\n }\n }\n\n await walk(dir);\n return results;\n}\n\n/**\n * Install pgvector extension into the embedded-postgres native directory.\n * Downloads from Homebrew bottles (GHCR) which cover macOS + Linux.\n */\nexport async function installPgVectorExtension(\n nativeDir: string,\n pgMajorVersion: string,\n): Promise<void> {\n const libDir = path.join(nativeDir, \"lib\", \"postgresql\");\n const extDir = path.join(nativeDir, \"share\", \"postgresql\", \"extension\");\n\n const soName = os.platform() === \"darwin\" ? \"vector.dylib\" : \"vector.so\";\n\n // Check if already installed\n try {\n await fs.access(path.join(libDir, soName));\n await fs.access(path.join(extDir, \"vector.control\"));\n return;\n } catch {\n // Not installed\n }\n\n const platform = os.platform();\n const arch = os.arch();\n const cacheDir = getCacheDir();\n const cacheKey = `pgvector-pg${pgMajorVersion}-${platform}-${arch}`;\n const cachedDir = path.join(cacheDir, cacheKey);\n\n // Check cache\n let cached = false;\n try {\n await fs.access(path.join(cachedDir, \"lib\", soName));\n cached = true;\n } catch {\n // Not cached\n }\n\n if (!cached) {\n const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), \"pgvector-\"));\n\n try {\n // Fetch Homebrew formula metadata to get bottle URLs\n const formulaRes = await fetch(\n \"https://formulae.brew.sh/api/formula/pgvector.json\",\n );\n if (!formulaRes.ok) {\n throw new Error(\n `Failed to fetch pgvector formula: ${formulaRes.status}`,\n );\n }\n const formula = (await formulaRes.json()) as HomebrewFormula;\n\n const bottleTag = getHomebrewBottleTag(platform, arch);\n const fileInfo = formula.bottle.stable.files[bottleTag];\n if (!fileInfo) {\n throw new Error(\n `No pgvector Homebrew bottle for ${bottleTag}. ` +\n `Available: ${Object.keys(formula.bottle.stable.files).join(\", \")}`,\n );\n }\n\n // Get anonymous GHCR auth token\n const tokenRes = await fetch(\n \"https://ghcr.io/token?scope=repository:homebrew/core/pgvector:pull\",\n );\n if (!tokenRes.ok) {\n throw new Error(`Failed to get GHCR token: ${tokenRes.status}`);\n }\n const { token } = (await tokenRes.json()) as { token: string };\n\n // Download the bottle blob\n const blobUrl = `https://ghcr.io/v2/homebrew/core/pgvector/blobs/sha256:${fileInfo.sha256}`;\n const blobRes = await fetch(blobUrl, {\n headers: { Authorization: `Bearer ${token}` },\n redirect: \"follow\",\n });\n if (!blobRes.ok) {\n throw new Error(\n `Failed to download pgvector bottle: ${blobRes.status}`,\n );\n }\n\n const bottlePath = path.join(tmpDir, \"pgvector.tar.gz\");\n const buffer = Buffer.from(await blobRes.arrayBuffer());\n await fs.writeFile(bottlePath, buffer);\n\n // Extract the tarball\n const extractDir = path.join(tmpDir, \"extracted\");\n await fs.mkdir(extractDir, { recursive: true });\n await execFile(\"tar\", [\"xzf\", bottlePath, \"-C\", extractDir]);\n\n // Cache extracted extension files\n const cacheLibDir = path.join(cachedDir, \"lib\");\n const cacheExtDir = path.join(cachedDir, \"extension\");\n await fs.mkdir(cacheLibDir, { recursive: true });\n await fs.mkdir(cacheExtDir, { recursive: true });\n\n // Find vector.so/.dylib for the matching PG version\n const pgSubdir = `postgresql@${pgMajorVersion}`;\n let soFiles = await findFiles(\n extractDir,\n new RegExp(`${pgSubdir}.*vector\\\\.(so|dylib)$`),\n );\n if (soFiles.length === 0) {\n soFiles = await findFiles(extractDir, /vector\\.(so|dylib)$/);\n }\n for (const f of soFiles) {\n await copyFileWithPermissions(f, path.join(cacheLibDir, path.basename(f)));\n }\n\n // Find extension control and SQL files for matching PG version\n let extFiles = await findFiles(\n extractDir,\n new RegExp(`${pgSubdir}.*vector[^/]*(\\\\.control|\\\\.sql)$`),\n );\n if (extFiles.length === 0) {\n extFiles = await findFiles(extractDir, /vector[^/]*(\\.control|\\.sql)$/);\n }\n for (const f of extFiles) {\n await copyFileWithPermissions(f, path.join(cacheExtDir, path.basename(f)));\n }\n } finally {\n await fs.rm(tmpDir, { recursive: true, force: true });\n }\n }\n\n // Copy from cache to native dir\n await fs.mkdir(libDir, { recursive: true });\n await fs.mkdir(extDir, { recursive: true });\n\n const cacheLibDir = path.join(cachedDir, \"lib\");\n const cacheExtDir = path.join(cachedDir, \"extension\");\n\n for (const file of await fs.readdir(cacheLibDir)) {\n await copyFileWithPermissions(path.join(cacheLibDir, file), path.join(libDir, file));\n }\n\n for (const file of await fs.readdir(cacheExtDir)) {\n await copyFileWithPermissions(path.join(cacheExtDir, file), path.join(extDir, file));\n }\n}\n\nfunction getHomebrewBottleTag(platform: string, arch: string): string {\n if (platform === \"darwin\") {\n const release = os.release();\n const major = parseInt(release.split(\".\")[0] ?? \"0\", 10);\n const prefix = arch === \"arm64\" ? \"arm64_\" : \"\";\n if (major >= 25) return `${prefix}tahoe`;\n if (major >= 24) return `${prefix}sequoia`;\n if (major >= 23) return `${prefix}sonoma`;\n return `${prefix}ventura`;\n }\n if (platform === \"linux\") {\n return arch === \"arm64\" ? \"aarch64_linux\" : \"x86_64_linux\";\n }\n throw new Error(`No Homebrew bottles available for ${platform}-${arch}`);\n}\n\ninterface HomebrewFormula {\n bottle: {\n stable: {\n files: Record<string, { cellar: string; sha256: string }>;\n };\n };\n}\n\n/**\n * Minimum age (ms) a directory must have before the orphan sweep will\n * consider deleting it. This avoids racing with concurrent test processes\n * that have just created their data dir but have not yet started postgres\n * (so no postmaster.pid file exists yet).\n */\nconst ORPHAN_MIN_AGE_MS = 60_000;\n\n/**\n * Sweep $TMPDIR for orphaned `postgres-memory-server-*` data directories\n * left behind by previous processes that crashed or were hard-killed.\n *\n * A directory is considered orphaned if:\n * - it is at least `minAgeMs` old, AND\n * - it has no `postmaster.pid` file (init never finished), OR\n * - the PID inside `postmaster.pid` no longer maps to a live process.\n *\n * The age check protects concurrent test processes that are mid-init.\n * Live directories whose postmaster.pid points to a running process are\n * always left alone, regardless of age.\n */\nexport async function sweepOrphanedDataDirs(\n minAgeMs: number = ORPHAN_MIN_AGE_MS,\n): Promise<void> {\n const tmpDir = os.tmpdir();\n let entries: string[];\n try {\n entries = await fs.readdir(tmpDir);\n } catch {\n return;\n }\n\n const cutoff = Date.now() - minAgeMs;\n\n await Promise.all(\n entries\n .filter((name) => name.startsWith(\"postgres-memory-server-\"))\n .map(async (name) => {\n const fullPath = path.join(tmpDir, name);\n let stat: import(\"node:fs\").Stats;\n try {\n stat = await fs.stat(fullPath);\n if (!stat.isDirectory()) return;\n } catch {\n return;\n }\n\n const pidFile = path.join(fullPath, \"postmaster.pid\");\n let pid: number | null = null;\n let pidFileExists = false;\n try {\n const content = await fs.readFile(pidFile, \"utf8\");\n pidFileExists = true;\n const firstLine = content.split(\"\\n\")[0]?.trim();\n const parsed = firstLine ? parseInt(firstLine, 10) : NaN;\n if (!Number.isNaN(parsed) && parsed > 0) {\n pid = parsed;\n }\n } catch {\n // No pid file\n }\n\n if (pid !== null) {\n try {\n // Signal 0 just checks whether the process exists.\n process.kill(pid, 0);\n // Process is alive — leave it alone, regardless of age.\n return;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"EPERM\") {\n // Process exists but belongs to another user — leave it alone.\n return;\n }\n // ESRCH or anything else means the process is dead.\n }\n }\n\n // No live PID. Apply the age check before deleting to avoid\n // racing with a concurrent test that just mkdtemp'd this dir\n // and has not yet finished initdb.\n if (!pidFileExists && stat.mtimeMs > cutoff) {\n return;\n }\n\n await fs.rm(fullPath, { recursive: true, force: true }).catch(() => {});\n }),\n );\n}\n\n/**\n * Parse a ParadeDB version string like \"0.22.5\" or \"0.22.5-pg17\".\n * Returns the extension version and optional PG version suffix.\n */\nexport function parseParadeDBVersion(version: string): {\n extVersion: string;\n pgVersion?: string;\n} {\n const match = version.match(/^(\\d+\\.\\d+\\.\\d+)(?:-pg(\\d+))?$/);\n if (!match || !match[1]) {\n return { extVersion: version };\n }\n return {\n extVersion: match[1],\n pgVersion: match[2],\n };\n}\n","import { getPgMajorVersion, parseParadeDBVersion } from \"./native.js\";\nimport type {\n NormalizedPostgresMemoryServerOptions,\n PostgresMemoryServerOptions,\n PostgresMemoryServerPreset,\n} from \"./types.js\";\n\nexport const DEFAULT_PARADEDB_EXT_VERSION = \"0.22.5\";\nexport const DEFAULT_POSTGRES_VERSION = getPgMajorVersion();\nexport const DEFAULT_PARADEDB_VERSION = `${DEFAULT_PARADEDB_EXT_VERSION}-pg${DEFAULT_POSTGRES_VERSION}`;\n\n/** Descriptive label for the postgres preset. */\nexport const DEFAULT_POSTGRES_IMAGE = `postgres:${DEFAULT_POSTGRES_VERSION}`;\n\n/** Descriptive label for the paradedb preset. */\nexport const DEFAULT_PARADEDB_IMAGE = `paradedb:${DEFAULT_PARADEDB_VERSION}`;\n\n// Keep old constants for backward compatibility\nexport const POSTGRES_IMAGE_REPOSITORY = \"postgres\";\nexport const PARADEDB_IMAGE_REPOSITORY = \"paradedb\";\n\nconst DEFAULT_DATABASE = \"testdb\";\nconst DEFAULT_USERNAME = \"testuser\";\nconst DEFAULT_PASSWORD = \"testpassword\";\n\nconst PARADEDB_DEFAULT_EXTENSIONS = [\"pg_search\", \"vector\"];\n\nexport function normalizeOptions(\n options: PostgresMemoryServerOptions = {},\n): NormalizedPostgresMemoryServerOptions {\n const preset = options.preset ?? \"postgres\";\n const version = options.version;\n const image = getImageLabel(preset, version);\n const database = options.database ?? DEFAULT_DATABASE;\n const username = options.username ?? DEFAULT_USERNAME;\n const password = options.password ?? DEFAULT_PASSWORD;\n const extensions = options.extensions ?? getDefaultExtensions(preset);\n const initSql = options.initSql ?? [];\n\n return {\n preset,\n version,\n image,\n database,\n username,\n password,\n extensions,\n initSql,\n };\n}\n\nexport function getImageForVersion(\n preset: PostgresMemoryServerPreset,\n version: string,\n): string {\n const repository =\n preset === \"paradedb\" ? PARADEDB_IMAGE_REPOSITORY : POSTGRES_IMAGE_REPOSITORY;\n\n return `${repository}:${version}`;\n}\n\nexport function getDefaultImage(preset: PostgresMemoryServerPreset): string {\n return preset === \"paradedb\" ? DEFAULT_PARADEDB_IMAGE : DEFAULT_POSTGRES_IMAGE;\n}\n\nfunction getImageLabel(\n preset: PostgresMemoryServerPreset,\n version?: string,\n): string {\n if (version) {\n return getImageForVersion(preset, version);\n }\n return getDefaultImage(preset);\n}\n\nexport function getDefaultExtensions(\n preset: PostgresMemoryServerPreset,\n): string[] {\n return preset === \"paradedb\" ? [...PARADEDB_DEFAULT_EXTENSIONS] : [];\n}\n\nexport function buildInitStatements(\n options: NormalizedPostgresMemoryServerOptions,\n): string[] {\n const extensionStatements = options.extensions.map(\n (extension) =>\n `CREATE EXTENSION IF NOT EXISTS ${quoteIdentifier(extension)};`,\n );\n\n return [...extensionStatements, ...options.initSql];\n}\n\n/**\n * Resolve the ParadeDB extension version from the user-provided version string.\n * Validates that any PG version suffix matches the installed embedded-postgres.\n */\nexport function resolveParadeDBVersion(version?: string): string {\n if (!version) {\n return DEFAULT_PARADEDB_EXT_VERSION;\n }\n\n const parsed = parseParadeDBVersion(version);\n\n if (parsed.pgVersion) {\n const installedPg = DEFAULT_POSTGRES_VERSION;\n if (parsed.pgVersion !== installedPg) {\n throw new Error(\n `ParadeDB version \"${version}\" targets PostgreSQL ${parsed.pgVersion}, ` +\n `but embedded-postgres provides PostgreSQL ${installedPg}. ` +\n `Install embedded-postgres@${parsed.pgVersion}.x to match, ` +\n `or use version \"${parsed.extVersion}\" without the -pg suffix.`,\n );\n }\n }\n\n return parsed.extVersion;\n}\n\nfunction quoteIdentifier(name: string): string {\n if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n return name;\n }\n\n return `\"${name.replaceAll('\"', '\"\"')}\"`;\n}\n"],"mappings":";;;AAAA,OAAOA,cAAa;;;ACApB,SAAS,YAAYC,KAAI,cAAc;AACvC,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,cAAa;AAEpB,OAAO,sBAAsB;AAC7B,SAAS,cAAmC;;;ACNrC,IAAM,4BAAN,cAAwC,MAAM;AAAA,EACnD,YAAY,SAAiB,SAAwB;AACnD,UAAM,SAAS,OAAO;AACtB,SAAK,OAAO,WAAW;AAAA,EACzB;AACF;AAEO,IAAM,2BAAN,cAAuC,0BAA0B;AAAA,EACtE,YAAY,UAAkB;AAC5B;AAAA,MACE,0DAA0D,QAAQ;AAAA,IAEpE;AAAA,EACF;AACF;AAEO,IAAM,qBAAN,cAAiC,0BAA0B;AAAA,EAChE,cAAc;AACZ,UAAM,oDAAoD;AAAA,EAC5D;AACF;AAEO,IAAM,wBAAN,cAAoC,0BAA0B;AAAA,EACnE,YAAY,eAAuB,OAAe;AAChD;AAAA,MACE,0BAA0B,aAAa,gBAAgB,OAAO,WAAW,EAAE,GAAG,KAAK;AAAA,MACnF,QAAQ,EAAE,MAAM,IAAI;AAAA,IACtB;AAAA,EACF;AACF;;;AC7BA,SAAS,YAAY,IAAI,cAAc,kBAAkB;AACzD,SAAS,qBAAqB;AAC9B,SAAS,YAAY,kBAAkB;AACvC,SAAS,iBAAiB;AAC1B,OAAO,SAAS;AAChB,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,IAAM,WAAW,UAAU,UAAU;AAKrC,eAAsB,cAA+B;AACnD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,SAAS,IAAI,aAAa;AAChC,WAAO,OAAO,GAAG,MAAM;AACrB,YAAM,EAAE,KAAK,IAAI,OAAO,QAAQ;AAChC,aAAO,MAAM,MAAM,QAAQ,IAAI,CAAC;AAAA,IAClC,CAAC;AACD,WAAO,GAAG,SAAS,MAAM;AAAA,EAC3B,CAAC;AACH;AAMO,SAAS,oBAA4B;AAE1C,QAAM,MAAM,cAAc,YAAY,GAAG;AACzC,QAAM,YAAY,IAAI,QAAQ,mBAAmB;AACjD,MAAI,MAAM,KAAK,QAAQ,SAAS;AAGhC,SAAO,QAAQ,KAAK,QAAQ,GAAG,GAAG;AAChC,UAAM,YAAY,KAAK,KAAK,KAAK,cAAc;AAC/C,QAAI;AACF,YAAM,UAAU,aAAa,WAAW,MAAM;AAC9C,YAAM,MAAM,KAAK,MAAM,OAAO;AAC9B,UAAI,IAAI,SAAS,uBAAuB,IAAI,SAAS;AACnD,cAAM,QAAQ,IAAI,QAAQ,MAAM,GAAG,EAAE,CAAC;AACtC,YAAI,MAAO,QAAO;AAAA,MACpB;AAAA,IACF,QAAQ;AAAA,IAER;AACA,UAAM,KAAK,QAAQ,GAAG;AAAA,EACxB;AAEA,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;AAMO,SAAS,eAAuB;AACrC,QAAM,WAAW,GAAG,SAAS;AAC7B,QAAM,OAAO,GAAG,KAAK;AAErB,QAAM,mBAA2D;AAAA,IAC/D,QAAQ;AAAA,MACN,OAAO;AAAA,MACP,KAAK;AAAA,IACP;AAAA,IACA,OAAO;AAAA,MACL,KAAK;AAAA,MACL,OAAO;AAAA,IACT;AAAA,IACA,OAAO;AAAA,MACL,KAAK;AAAA,IACP;AAAA,EACF;AAEA,QAAM,UAAU,iBAAiB,QAAQ,IAAI,IAAI;AACjD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,yBAAyB,QAAQ,IAAI,IAAI,EAAE;AAAA,EAC7D;AAEA,QAAM,MAAM,cAAc,YAAY,GAAG;AAEzC,QAAM,YAAY,IAAI,QAAQ,OAAO;AACrC,MAAI,MAAM,KAAK,QAAQ,SAAS;AAGhC,SAAO,QAAQ,KAAK,QAAQ,GAAG,GAAG;AAChC,UAAM,YAAY,KAAK,KAAK,KAAK,QAAQ;AACzC,QAAI,WAAW,SAAS,GAAG;AACzB,aAAO;AAAA,IACT;AACA,UAAM,KAAK,QAAQ,GAAG;AAAA,EACxB;AAEA,QAAM,IAAI;AAAA,IACR,uCAAuC,OAAO;AAAA,EAChD;AACF;AAKO,SAAS,cAAsB;AACpC,QAAM,WAAW,QAAQ,IAAI;AAC7B,QAAM,OAAO,YAAY,KAAK,KAAK,GAAG,QAAQ,GAAG,QAAQ;AACzD,SAAO,KAAK,KAAK,MAAM,wBAAwB;AACjD;AAMA,eAAsB,yBACpB,WACA,iBACA,gBACe;AAEf,QAAM,SAAS,KAAK,KAAK,WAAW,OAAO,YAAY;AACvD,QAAM,SAAS,KAAK,KAAK,WAAW,SAAS,cAAc,WAAW;AAEtE,QAAM,SACJ,GAAG,SAAS,MAAM,YAAY,SAAS,gBAAgB,EAAE,KAAK,KAC1D,oBACA;AAEN,MAAI;AACF,UAAM,GAAG,OAAO,KAAK,KAAK,QAAQ,MAAM,CAAC;AACzC,UAAM,GAAG,OAAO,KAAK,KAAK,QAAQ,mBAAmB,CAAC;AACtD;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,QAAM,WAAW,YAAY;AAC7B,QAAM,WAAW,GAAG,SAAS;AAC7B,QAAM,OAAO,GAAG,KAAK;AACrB,QAAM,WAAW,YAAY,eAAe,MAAM,cAAc,IAAI,QAAQ,IAAI,IAAI;AACpF,QAAM,YAAY,KAAK,KAAK,UAAU,QAAQ;AAG9C,MAAI,SAAS;AACb,MAAI;AACF,UAAM,GAAG,OAAO,KAAK,KAAK,WAAW,OAAO,MAAM,CAAC;AACnD,aAAS;AAAA,EACX,QAAQ;AAAA,EAER;AAEA,MAAI,CAAC,QAAQ;AACX,UAAM,MAAM;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,SAAS,MAAM,GAAG,QAAQ,KAAK,KAAK,GAAG,OAAO,GAAG,WAAW,CAAC;AAEnE,QAAI;AACF,YAAM,WAAW,mBAAmB,IAAI,MAAM,GAAG,EAAE,IAAI,CAAE;AACzD,YAAM,cAAc,KAAK,KAAK,QAAQ,QAAQ;AAE9C,YAAM,aAAa,KAAK,WAAW;AAEnC,YAAM,eAAe,KAAK,KAAK,QAAQ,WAAW;AAClD,YAAM,GAAG,MAAM,cAAc,EAAE,WAAW,KAAK,CAAC;AAEhD,UAAI,aAAa,UAAU;AACzB,cAAM,WAAW,aAAa,YAAY;AAAA,MAC5C,OAAO;AACL,cAAM,WAAW,aAAa,YAAY;AAAA,MAC5C;AAGA,YAAMC,eAAc,KAAK,KAAK,WAAW,KAAK;AAC9C,YAAMC,eAAc,KAAK,KAAK,WAAW,WAAW;AACpD,YAAM,GAAG,MAAMD,cAAa,EAAE,WAAW,KAAK,CAAC;AAC/C,YAAM,GAAG,MAAMC,cAAa,EAAE,WAAW,KAAK,CAAC;AAE/C,YAAM,UAAU,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AACA,iBAAW,UAAU,SAAS;AAC5B,cAAM,wBAAwB,QAAQ,KAAK,KAAKD,cAAa,KAAK,SAAS,MAAM,CAAC,CAAC;AAAA,MACrF;AAEA,YAAM,WAAW,MAAM;AAAA,QACrB;AAAA,QACA;AAAA,MACF;AACA,iBAAW,WAAW,UAAU;AAC9B,cAAM;AAAA,UACJ;AAAA,UACA,KAAK,KAAKC,cAAa,KAAK,SAAS,OAAO,CAAC;AAAA,QAC/C;AAAA,MACF;AAAA,IACF,UAAE;AACA,YAAM,GAAG,GAAG,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACtD;AAAA,EACF;AAGA,QAAM,GAAG,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AAC1C,QAAM,GAAG,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AAE1C,QAAM,cAAc,KAAK,KAAK,WAAW,KAAK;AAC9C,QAAM,cAAc,KAAK,KAAK,WAAW,WAAW;AAEpD,aAAW,QAAQ,MAAM,GAAG,QAAQ,WAAW,GAAG;AAChD,UAAM,wBAAwB,KAAK,KAAK,aAAa,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,CAAC;AAAA,EACrF;AAEA,aAAW,QAAQ,MAAM,GAAG,QAAQ,WAAW,GAAG;AAChD,UAAM,wBAAwB,KAAK,KAAK,aAAa,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,CAAC;AAAA,EACrF;AACF;AAEA,SAAS,iBACP,SACA,gBACA,UACA,MACQ;AACR,QAAM,OAAO,2DAA2D,OAAO;AAE/E,MAAI,aAAa,UAAU;AACzB,QAAI,SAAS,SAAS;AACpB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,YAAY,iBAAiB;AACnC,WAAO,GAAG,IAAI,gBAAgB,cAAc,KAAK,OAAO,UAAU,SAAS;AAAA,EAC7E;AAEA,MAAI,aAAa,SAAS;AACxB,UAAM,UAAU,SAAS,UAAU,UAAU;AAC7C,WAAO,GAAG,IAAI,eAAe,cAAc,cAAc,OAAO,uBAAuB,OAAO;AAAA,EAChG;AAEA,QAAM,IAAI;AAAA,IACR,mDAAmD,QAAQ;AAAA,EAC7D;AACF;AAEA,SAAS,mBAA2B;AAClC,QAAM,UAAU,GAAG,QAAQ;AAC3B,QAAM,eAAe,SAAS,QAAQ,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE;AAE9D,MAAI,gBAAgB,GAAI,QAAO;AAC/B,MAAI,gBAAgB,GAAI,QAAO;AAC/B,QAAM,IAAI;AAAA,IACR,iEAAiE,OAAO;AAAA,EAC1E;AACF;AAEA,eAAe,aAAa,KAAa,UAAiC;AACxE,QAAM,WAAW,MAAM,MAAM,KAAK,EAAE,UAAU,SAAS,CAAC;AAExD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI;AAAA,MACR,8CAA8C,GAAG,KAAK,SAAS,MAAM,IAAI,SAAS,UAAU;AAAA,IAC9F;AAAA,EACF;AAEA,QAAM,SAAS,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC;AACvD,QAAM,GAAG,UAAU,UAAU,MAAM;AACrC;AAEA,eAAe,WACb,SACA,YACe;AACf,QAAM,SAAS,MAAM,CAAC,KAAK,OAAO,GAAG,EAAE,KAAK,WAAW,CAAC;AAExD,QAAM,QAAQ,MAAM,GAAG,QAAQ,UAAU;AACzC,QAAM,UAAU,MAAM,KAAK,CAAC,MAAM,EAAE,WAAW,UAAU,CAAC;AAE1D,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,KAAK,KAAK,YAAY,MAAM;AAC5C,QAAM,GAAG,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAC3C,QAAM,SAAS,OAAO;AAAA,IACpB;AAAA,IACA,KAAK,KAAK,YAAY,OAAO;AAAA,IAC7B;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEA,eAAe,WACb,SACA,YACe;AACf,QAAM,SAAS,KAAK,KAAK,YAAY,KAAK;AAC1C,QAAM,SAAS,WAAW,CAAC,iBAAiB,SAAS,MAAM,CAAC;AAC9D;AAMA,eAAe,wBACb,KACA,MACe;AACf,QAAM,UAAU,MAAM,GAAG,SAAS,GAAG;AACrC,QAAM,GAAG,UAAU,MAAM,SAAS,EAAE,MAAM,IAAM,CAAC;AACnD;AAEA,eAAe,UAAU,KAAa,SAAoC;AACxE,QAAM,UAAoB,CAAC;AAE3B,iBAAe,KAAK,YAAmC;AACrD,UAAM,UAAU,MAAM,GAAG,QAAQ,YAAY,EAAE,eAAe,KAAK,CAAC;AACpE,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAW,KAAK,KAAK,YAAY,MAAM,IAAI;AACjD,UAAI,MAAM,YAAY,GAAG;AACvB,cAAM,KAAK,QAAQ;AAAA,MACrB,WAAW,QAAQ,KAAK,MAAM,IAAI,GAAG;AACnC,gBAAQ,KAAK,QAAQ;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,KAAK,GAAG;AACd,SAAO;AACT;AAMA,eAAsB,yBACpB,WACA,gBACe;AACf,QAAM,SAAS,KAAK,KAAK,WAAW,OAAO,YAAY;AACvD,QAAM,SAAS,KAAK,KAAK,WAAW,SAAS,cAAc,WAAW;AAEtE,QAAM,SAAS,GAAG,SAAS,MAAM,WAAW,iBAAiB;AAG7D,MAAI;AACF,UAAM,GAAG,OAAO,KAAK,KAAK,QAAQ,MAAM,CAAC;AACzC,UAAM,GAAG,OAAO,KAAK,KAAK,QAAQ,gBAAgB,CAAC;AACnD;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,QAAM,WAAW,GAAG,SAAS;AAC7B,QAAM,OAAO,GAAG,KAAK;AACrB,QAAM,WAAW,YAAY;AAC7B,QAAM,WAAW,cAAc,cAAc,IAAI,QAAQ,IAAI,IAAI;AACjE,QAAM,YAAY,KAAK,KAAK,UAAU,QAAQ;AAG9C,MAAI,SAAS;AACb,MAAI;AACF,UAAM,GAAG,OAAO,KAAK,KAAK,WAAW,OAAO,MAAM,CAAC;AACnD,aAAS;AAAA,EACX,QAAQ;AAAA,EAER;AAEA,MAAI,CAAC,QAAQ;AACX,UAAM,SAAS,MAAM,GAAG,QAAQ,KAAK,KAAK,GAAG,OAAO,GAAG,WAAW,CAAC;AAEnE,QAAI;AAEF,YAAM,aAAa,MAAM;AAAA,QACvB;AAAA,MACF;AACA,UAAI,CAAC,WAAW,IAAI;AAClB,cAAM,IAAI;AAAA,UACR,qCAAqC,WAAW,MAAM;AAAA,QACxD;AAAA,MACF;AACA,YAAM,UAAW,MAAM,WAAW,KAAK;AAEvC,YAAM,YAAY,qBAAqB,UAAU,IAAI;AACrD,YAAM,WAAW,QAAQ,OAAO,OAAO,MAAM,SAAS;AACtD,UAAI,CAAC,UAAU;AACb,cAAM,IAAI;AAAA,UACR,mCAAmC,SAAS,gBAC5B,OAAO,KAAK,QAAQ,OAAO,OAAO,KAAK,EAAE,KAAK,IAAI,CAAC;AAAA,QACrE;AAAA,MACF;AAGA,YAAM,WAAW,MAAM;AAAA,QACrB;AAAA,MACF;AACA,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,MAAM,6BAA6B,SAAS,MAAM,EAAE;AAAA,MAChE;AACA,YAAM,EAAE,MAAM,IAAK,MAAM,SAAS,KAAK;AAGvC,YAAM,UAAU,0DAA0D,SAAS,MAAM;AACzF,YAAM,UAAU,MAAM,MAAM,SAAS;AAAA,QACnC,SAAS,EAAE,eAAe,UAAU,KAAK,GAAG;AAAA,QAC5C,UAAU;AAAA,MACZ,CAAC;AACD,UAAI,CAAC,QAAQ,IAAI;AACf,cAAM,IAAI;AAAA,UACR,uCAAuC,QAAQ,MAAM;AAAA,QACvD;AAAA,MACF;AAEA,YAAM,aAAa,KAAK,KAAK,QAAQ,iBAAiB;AACtD,YAAM,SAAS,OAAO,KAAK,MAAM,QAAQ,YAAY,CAAC;AACtD,YAAM,GAAG,UAAU,YAAY,MAAM;AAGrC,YAAM,aAAa,KAAK,KAAK,QAAQ,WAAW;AAChD,YAAM,GAAG,MAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AAC9C,YAAM,SAAS,OAAO,CAAC,OAAO,YAAY,MAAM,UAAU,CAAC;AAG3D,YAAMD,eAAc,KAAK,KAAK,WAAW,KAAK;AAC9C,YAAMC,eAAc,KAAK,KAAK,WAAW,WAAW;AACpD,YAAM,GAAG,MAAMD,cAAa,EAAE,WAAW,KAAK,CAAC;AAC/C,YAAM,GAAG,MAAMC,cAAa,EAAE,WAAW,KAAK,CAAC;AAG/C,YAAM,WAAW,cAAc,cAAc;AAC7C,UAAI,UAAU,MAAM;AAAA,QAClB;AAAA,QACA,IAAI,OAAO,GAAG,QAAQ,wBAAwB;AAAA,MAChD;AACA,UAAI,QAAQ,WAAW,GAAG;AACxB,kBAAU,MAAM,UAAU,YAAY,qBAAqB;AAAA,MAC7D;AACA,iBAAW,KAAK,SAAS;AACvB,cAAM,wBAAwB,GAAG,KAAK,KAAKD,cAAa,KAAK,SAAS,CAAC,CAAC,CAAC;AAAA,MAC3E;AAGA,UAAI,WAAW,MAAM;AAAA,QACnB;AAAA,QACA,IAAI,OAAO,GAAG,QAAQ,mCAAmC;AAAA,MAC3D;AACA,UAAI,SAAS,WAAW,GAAG;AACzB,mBAAW,MAAM,UAAU,YAAY,+BAA+B;AAAA,MACxE;AACA,iBAAW,KAAK,UAAU;AACxB,cAAM,wBAAwB,GAAG,KAAK,KAAKC,cAAa,KAAK,SAAS,CAAC,CAAC,CAAC;AAAA,MAC3E;AAAA,IACF,UAAE;AACA,YAAM,GAAG,GAAG,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACtD;AAAA,EACF;AAGA,QAAM,GAAG,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AAC1C,QAAM,GAAG,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AAE1C,QAAM,cAAc,KAAK,KAAK,WAAW,KAAK;AAC9C,QAAM,cAAc,KAAK,KAAK,WAAW,WAAW;AAEpD,aAAW,QAAQ,MAAM,GAAG,QAAQ,WAAW,GAAG;AAChD,UAAM,wBAAwB,KAAK,KAAK,aAAa,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,CAAC;AAAA,EACrF;AAEA,aAAW,QAAQ,MAAM,GAAG,QAAQ,WAAW,GAAG;AAChD,UAAM,wBAAwB,KAAK,KAAK,aAAa,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,CAAC;AAAA,EACrF;AACF;AAEA,SAAS,qBAAqB,UAAkB,MAAsB;AACpE,MAAI,aAAa,UAAU;AACzB,UAAM,UAAU,GAAG,QAAQ;AAC3B,UAAM,QAAQ,SAAS,QAAQ,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE;AACvD,UAAM,SAAS,SAAS,UAAU,WAAW;AAC7C,QAAI,SAAS,GAAI,QAAO,GAAG,MAAM;AACjC,QAAI,SAAS,GAAI,QAAO,GAAG,MAAM;AACjC,QAAI,SAAS,GAAI,QAAO,GAAG,MAAM;AACjC,WAAO,GAAG,MAAM;AAAA,EAClB;AACA,MAAI,aAAa,SAAS;AACxB,WAAO,SAAS,UAAU,kBAAkB;AAAA,EAC9C;AACA,QAAM,IAAI,MAAM,qCAAqC,QAAQ,IAAI,IAAI,EAAE;AACzE;AAgBA,IAAM,oBAAoB;AAe1B,eAAsB,sBACpB,WAAmB,mBACJ;AACf,QAAM,SAAS,GAAG,OAAO;AACzB,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,GAAG,QAAQ,MAAM;AAAA,EACnC,QAAQ;AACN;AAAA,EACF;AAEA,QAAM,SAAS,KAAK,IAAI,IAAI;AAE5B,QAAM,QAAQ;AAAA,IACZ,QACG,OAAO,CAAC,SAAS,KAAK,WAAW,yBAAyB,CAAC,EAC3D,IAAI,OAAO,SAAS;AACnB,YAAM,WAAW,KAAK,KAAK,QAAQ,IAAI;AACvC,UAAI;AACJ,UAAI;AACF,eAAO,MAAM,GAAG,KAAK,QAAQ;AAC7B,YAAI,CAAC,KAAK,YAAY,EAAG;AAAA,MAC3B,QAAQ;AACN;AAAA,MACF;AAEA,YAAM,UAAU,KAAK,KAAK,UAAU,gBAAgB;AACpD,UAAI,MAAqB;AACzB,UAAI,gBAAgB;AACpB,UAAI;AACF,cAAM,UAAU,MAAM,GAAG,SAAS,SAAS,MAAM;AACjD,wBAAgB;AAChB,cAAM,YAAY,QAAQ,MAAM,IAAI,EAAE,CAAC,GAAG,KAAK;AAC/C,cAAM,SAAS,YAAY,SAAS,WAAW,EAAE,IAAI;AACrD,YAAI,CAAC,OAAO,MAAM,MAAM,KAAK,SAAS,GAAG;AACvC,gBAAM;AAAA,QACR;AAAA,MACF,QAAQ;AAAA,MAER;AAEA,UAAI,QAAQ,MAAM;AAChB,YAAI;AAEF,kBAAQ,KAAK,KAAK,CAAC;AAEnB;AAAA,QACF,SAAS,KAAK;AACZ,gBAAM,OAAQ,IAA8B;AAC5C,cAAI,SAAS,SAAS;AAEpB;AAAA,UACF;AAAA,QAEF;AAAA,MACF;AAKA,UAAI,CAAC,iBAAiB,KAAK,UAAU,QAAQ;AAC3C;AAAA,MACF;AAEA,YAAM,GAAG,GAAG,UAAU,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACxE,CAAC;AAAA,EACL;AACF;AAMO,SAAS,qBAAqB,SAGnC;AACA,QAAM,QAAQ,QAAQ,MAAM,gCAAgC;AAC5D,MAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG;AACvB,WAAO,EAAE,YAAY,QAAQ;AAAA,EAC/B;AACA,SAAO;AAAA,IACL,YAAY,MAAM,CAAC;AAAA,IACnB,WAAW,MAAM,CAAC;AAAA,EACpB;AACF;;;ACzlBO,IAAM,+BAA+B;AACrC,IAAM,2BAA2B,kBAAkB;AACnD,IAAM,2BAA2B,GAAG,4BAA4B,MAAM,wBAAwB;AAG9F,IAAM,yBAAyB,YAAY,wBAAwB;AAGnE,IAAM,yBAAyB,YAAY,wBAAwB;AAGnE,IAAM,4BAA4B;AAClC,IAAM,4BAA4B;AAEzC,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AAEzB,IAAM,8BAA8B,CAAC,aAAa,QAAQ;AAEnD,SAAS,iBACd,UAAuC,CAAC,GACD;AACvC,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,UAAU,QAAQ;AACxB,QAAM,QAAQ,cAAc,QAAQ,OAAO;AAC3C,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,aAAa,QAAQ,cAAc,qBAAqB,MAAM;AACpE,QAAM,UAAU,QAAQ,WAAW,CAAC;AAEpC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,mBACd,QACA,SACQ;AACR,QAAM,aACJ,WAAW,aAAa,4BAA4B;AAEtD,SAAO,GAAG,UAAU,IAAI,OAAO;AACjC;AAEO,SAAS,gBAAgB,QAA4C;AAC1E,SAAO,WAAW,aAAa,yBAAyB;AAC1D;AAEA,SAAS,cACP,QACA,SACQ;AACR,MAAI,SAAS;AACX,WAAO,mBAAmB,QAAQ,OAAO;AAAA,EAC3C;AACA,SAAO,gBAAgB,MAAM;AAC/B;AAEO,SAAS,qBACd,QACU;AACV,SAAO,WAAW,aAAa,CAAC,GAAG,2BAA2B,IAAI,CAAC;AACrE;AAEO,SAAS,oBACd,SACU;AACV,QAAM,sBAAsB,QAAQ,WAAW;AAAA,IAC7C,CAAC,cACC,kCAAkC,gBAAgB,SAAS,CAAC;AAAA,EAChE;AAEA,SAAO,CAAC,GAAG,qBAAqB,GAAG,QAAQ,OAAO;AACpD;AAMO,SAAS,uBAAuB,SAA0B;AAC/D,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,qBAAqB,OAAO;AAE3C,MAAI,OAAO,WAAW;AACpB,UAAM,cAAc;AACpB,QAAI,OAAO,cAAc,aAAa;AACpC,YAAM,IAAI;AAAA,QACR,qBAAqB,OAAO,wBAAwB,OAAO,SAAS,+CACrB,WAAW,+BAC3B,OAAO,SAAS,gCAC1B,OAAO,UAAU;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,OAAO;AAChB;AAEA,SAAS,gBAAgB,MAAsB;AAC7C,MAAI,2BAA2B,KAAK,IAAI,GAAG;AACzC,WAAO;AAAA,EACT;AAEA,SAAO,IAAI,KAAK,WAAW,KAAK,IAAI,CAAC;AACvC;;;AHzFA,IAAM,gBAAgB,oBAAI,IAA0B;AACpD,IAAI,yBAAyB;AAC7B,IAAI,kBAAkB;AAEtB,SAAS,uBAA6B;AACpC,MAAI,uBAAwB;AAC5B,2BAAyB;AAEzB,QAAM,UAAU,MAAM;AACpB,eAAW,YAAY,eAAe;AACpC,UAAI;AACF,iBAAS,aAAa;AAAA,MACxB,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,EAAAC,SAAQ,KAAK,QAAQ,OAAO;AAI5B,QAAM,gBAAgB,CAAC,WAA2B;AAChD,YAAQ;AAER,IAAAA,SAAQ,eAAe,QAAQ,aAAa;AAC5C,IAAAA,SAAQ,KAAKA,SAAQ,KAAK,MAAM;AAAA,EAClC;AACA,EAAAA,SAAQ,GAAG,UAAU,aAAa;AAClC,EAAAA,SAAQ,GAAG,WAAW,aAAa;AACnC,EAAAA,SAAQ,GAAG,UAAU,aAAa;AACpC;AAEO,IAAM,uBAAN,MAAM,sBAAqB;AAAA,EAKxB,YACW,IACA,MACA,SACA,SACjB;AAJiB;AACA;AACA;AACA;AAEjB,SAAK,oBAAoB,QAAQ,aAAa;AAAA,EAChD;AAAA,EAXQ,UAAU;AAAA,EACD;AAAA,EACT,cAAc;AAAA,EAWtB,aAAa,OACX,UAAuC,CAAC,GACT;AAE/B,QAAI,CAAC,iBAAiB;AACpB,wBAAkB;AAClB,YAAM,sBAAsB,EAAE,MAAM,MAAM;AAAA,MAE1C,CAAC;AAAA,IACH;AAEA,UAAM,aAAa,iBAAiB,OAAO;AAC3C,UAAM,OAAO,MAAM,YAAY;AAC/B,UAAM,UAAU,MAAMC,IAAG;AAAA,MACvBC,MAAK,KAAKC,IAAG,OAAO,GAAG,yBAAyB;AAAA,IAClD;AAEA,QAAI;AAEJ,QAAI;AACF,YAAM,gBAA0B,CAAC;AAGjC,UAAI,WAAW,WAAW,YAAY;AACpC,cAAM,YAAY,aAAa;AAC/B,cAAM,aAAa,uBAAuB,WAAW,OAAO;AAC5D,cAAM,UAAU;AAEhB,YAAI;AACF,gBAAM,yBAAyB,WAAW,YAAY,OAAO;AAAA,QAC/D,SAAS,OAAO;AACd,gBAAM,IAAI;AAAA,YACR;AAAA,YACA,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,UAC1D;AAAA,QACF;AAEA,YAAI,WAAW,WAAW,SAAS,QAAQ,GAAG;AAC5C,cAAI;AACF,kBAAM,yBAAyB,WAAW,OAAO;AAAA,UACnD,SAAS,OAAO;AACd,kBAAM,IAAI;AAAA,cACR;AAAA,cACA,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,YAC1D;AAAA,UACF;AAAA,QACF;AAEA,YACE,WAAW,WAAW,SAAS,WAAW,KAC1C,WAAW,WAAW,WAAW,GACjC;AACA,wBAAc,KAAK,MAAM,oCAAoC;AAAA,QAC/D;AAAA,MACF;AAEA,WAAK,IAAI,iBAAiB;AAAA,QACxB,aAAa;AAAA,QACb;AAAA,QACA,MAAM,WAAW;AAAA,QACjB,UAAU,WAAW;AAAA,QACrB,YAAY;AAAA,QACZ;AAAA,QACA,OAAO,MAAM;AAAA,QAAC;AAAA,QACd,SAAS,MAAM;AAAA,QAAC;AAAA,MAClB,CAAC;AAED,YAAM,GAAG,WAAW;AACpB,YAAM,GAAG,MAAM;AAEf,UAAI,WAAW,aAAa,YAAY;AACtC,cAAM,GAAG,eAAe,WAAW,QAAQ;AAAA,MAC7C;AAEA,YAAM,SAAS,IAAI,sBAAqB,IAAI,MAAM,SAAS,UAAU;AACrE,oBAAc,IAAI,MAAM;AACxB,2BAAqB;AAErB,YAAM,iBAAiB,oBAAoB,UAAU;AACrD,UAAI,eAAe,SAAS,GAAG;AAC7B,cAAM,OAAO,OAAO,cAAc;AAAA,MACpC;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AAEd,UAAI,IAAI;AACN,YAAI;AACF,gBAAM,GAAG,KAAK;AAAA,QAChB,QAAQ;AAAA,QAER;AAAA,MACF;AACA,YAAMF,IACH,GAAG,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC,EAC5C,MAAM,MAAM;AAAA,MAAC,CAAC;AACjB,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,OAAO,eACL,UAAuD,CAAC,GACzB;AAC/B,WAAO,sBAAqB,OAAO,EAAE,GAAG,SAAS,QAAQ,WAAW,CAAC;AAAA,EACvE;AAAA,EAEA,OAAO,eACL,UAAuD,CAAC,GACzB;AAC/B,WAAO,sBAAqB,OAAO,EAAE,GAAG,SAAS,QAAQ,WAAW,CAAC;AAAA,EACvE;AAAA,EAEA,SAAiB;AACf,SAAK,cAAc;AACnB,WAAO,cAAc,KAAK,QAAQ,QAAQ,IAAI,KAAK,QAAQ,QAAQ,cAAc,KAAK,IAAI,IAAI,KAAK,QAAQ,QAAQ;AAAA,EACrH;AAAA,EAEA,UAAkB;AAChB,SAAK,cAAc;AACnB,WAAO;AAAA,EACT;AAAA,EAEA,UAAkB;AAChB,SAAK,cAAc;AACnB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,cAAsB;AACpB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAEA,cAAsB;AACpB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAEA,cAAsB;AACpB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAEA,WAAmB;AACjB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAqB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,uBAAkD;AAChD,WAAO;AAAA,MACL,MAAM,KAAK,QAAQ;AAAA,MACnB,MAAM,KAAK,QAAQ;AAAA,MACnB,UAAU,KAAK,YAAY;AAAA,MAC3B,MAAM,KAAK,YAAY;AAAA,MACvB,UAAU,KAAK,YAAY;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAM,MACJ,MACA,QAC6B;AAC7B,WAAO,KAAK,WAAW,CAAC,WAAW;AACjC,UAAI,OAAO,SAAS,UAAU;AAC5B,YAAI,WAAW,QAAW;AACxB,iBAAO,OAAO,MAAW,IAAI;AAAA,QAC/B;AAEA,eAAO,OAAO,MAAW,MAAM,MAAM;AAAA,MACvC;AAEA,aAAO,OAAO,MAAW,IAAI;AAAA,IAC/B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,WAAc,UAAsD;AACxE,SAAK,cAAc;AAEnB,UAAM,SAAS,IAAI,OAAO;AAAA,MACxB,kBAAkB,KAAK,OAAO;AAAA,IAChC,CAAC;AAED,UAAM,OAAO,QAAQ;AACrB,QAAI;AACF,aAAO,MAAM,SAAS,MAAM;AAAA,IAC9B,UAAE;AACA,YAAM,OAAO,IAAI;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,KAAuC;AAClD,UAAM,aAAa,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,GAAG;AAElD,UAAM,KAAK,WAAW,OAAO,WAAW;AACtC,iBAAW,aAAa,YAAY;AAClC,cAAM,OAAO,MAAM,SAAS;AAAA,MAC9B;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,WAAW,UAAiC;AAChD,UAAM,MAAM,MAAMA,IAAG,SAAS,UAAU,MAAM;AAC9C,UAAM,KAAK,OAAO,GAAG;AAAA,EACvB;AAAA,EAEA,MAAM,iBAAiB,SAAoC;AACzD,UAAM,UAAU,MAAMA,IAAG,QAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AACjE,UAAM,QAAQ,QACX;AAAA,MACC,CAAC,UAAU,MAAM,OAAO,KAAK,MAAM,KAAK,YAAY,EAAE,SAAS,MAAM;AAAA,IACvE,EACC,IAAI,CAAC,UAAU,MAAM,IAAI,EACzB,KAAK,CAAC,MAAM,UAAU,KAAK,cAAc,KAAK,CAAC;AAElD,eAAW,QAAQ,OAAO;AACxB,YAAM,KAAK,WAAWC,MAAK,KAAK,SAAS,IAAI,CAAC;AAAA,IAChD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAA0B;AAC9B,SAAK,cAAc;AACnB,SAAK,wBAAwB;AAE7B,UAAM,aAAa,GAAG,KAAK,QAAQ,QAAQ;AAE3C,UAAM,KAAK,gBAAgB,OAAO,WAAW;AAE3C,YAAM,OAAO;AAAA,QACX;AAAA,QACA,CAAC,KAAK,QAAQ,QAAQ;AAAA,MACxB;AAGA,UAAI,KAAK,aAAa;AACpB,cAAM,OAAO,MAAM,4BAA4B,UAAU,GAAG;AAAA,MAC9D;AAGA,YAAM,OAAO;AAAA,QACX,oBAAoB,UAAU,eAAe,KAAK,QAAQ,QAAQ;AAAA,MACpE;AAAA,IACF,CAAC;AAED,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,UAAyB;AAC7B,SAAK,cAAc;AACnB,SAAK,wBAAwB;AAE7B,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAa,GAAG,KAAK,QAAQ,QAAQ;AAE3C,UAAM,KAAK,gBAAgB,OAAO,WAAW;AAE3C,YAAM,OAAO;AAAA,QACX;AAAA,QACA,CAAC,KAAK,QAAQ,QAAQ;AAAA,MACxB;AAGA,YAAM,OAAO,MAAM,kBAAkB,KAAK,QAAQ,QAAQ,GAAG;AAC7D,YAAM,OAAO;AAAA,QACX,oBAAoB,KAAK,QAAQ,QAAQ,eAAe,UAAU;AAAA,MACpE;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI,KAAK,SAAS;AAChB;AAAA,IACF;AAEA,SAAK,UAAU;AACf,kBAAc,OAAO,IAAI;AAEzB,QAAI;AACF,YAAM,KAAK,GAAG,KAAK;AAAA,IACrB,QAAQ;AAAA,IAGR;AAKA,UAAMD,IACH,GAAG,KAAK,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC,EACjD,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,eAAqB;AACnB,QAAI,KAAK,SAAS;AAChB;AAAA,IACF;AACA,SAAK,UAAU;AACf,kBAAc,OAAO,IAAI;AACzB,QAAI;AACF,aAAO,KAAK,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACvD,QAAQ;AAAA,IAER;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,gBACZ,UACY;AACZ,UAAM,SAAS,IAAI,OAAO;AAAA,MACxB,MAAM;AAAA,MACN,MAAM,KAAK;AAAA,MACX,UAAU;AAAA,MACV,MAAM,KAAK,QAAQ;AAAA,MACnB,UAAU,KAAK,QAAQ;AAAA,IACzB,CAAC;AAED,UAAM,OAAO,QAAQ;AACrB,QAAI;AACF,aAAO,MAAM,SAAS,MAAM;AAAA,IAC9B,UAAE;AACA,YAAM,OAAO,IAAI;AAAA,IACnB;AAAA,EACF;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,SAAS;AAChB,YAAM,IAAI,mBAAmB;AAAA,IAC/B;AAAA,EACF;AAAA,EAEQ,0BAAgC;AACtC,QAAI,CAAC,KAAK,mBAAmB;AAC3B,YAAM,IAAI,yBAAyB,KAAK,QAAQ,QAAQ;AAAA,IAC1D;AAAA,EACF;AACF;;;ADvbA,eAAe,OAAsB;AACnC,QAAM,EAAE,SAAS,WAAW,KAAK,IAAI,UAAUG,SAAQ,KAAK,MAAM,CAAC,CAAC;AAEpE,QAAM,SAAS,MAAM,qBAAqB,OAAO,OAAO;AAExD,MAAI;AACF,eAAW,QAAQ,WAAW;AAC5B,YAAM,OAAO,WAAW,IAAI;AAAA,IAC9B;AAEA,UAAM,UAAU;AAAA,MACd,KAAK,OAAO,OAAO;AAAA,MACnB,MAAM,OAAO,QAAQ;AAAA,MACrB,MAAM,OAAO,QAAQ;AAAA,MACrB,UAAU,OAAO,YAAY;AAAA,MAC7B,UAAU,OAAO,YAAY;AAAA,MAC7B,UAAU,OAAO,YAAY;AAAA,MAC7B,OAAO,OAAO,SAAS;AAAA,IACzB;AAEA,QAAI,MAAM;AACR,MAAAA,SAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,IAC9D,OAAO;AACL,MAAAA,SAAQ,OAAO,MAAM,8BAA8B,QAAQ,GAAG;AAAA,CAAI;AAClE,MAAAA,SAAQ,OAAO,MAAM,+BAA+B,QAAQ,IAAI;AAAA,CAAI;AACpE,MAAAA,SAAQ,OAAO,MAAM,+BAA+B,QAAQ,IAAI;AAAA,CAAI;AACpE,MAAAA,SAAQ,OAAO;AAAA,QACb,mCAAmC,QAAQ,QAAQ;AAAA;AAAA,MACrD;AACA,MAAAA,SAAQ,OAAO;AAAA,QACb,mCAAmC,QAAQ,QAAQ;AAAA;AAAA,MACrD;AACA,MAAAA,SAAQ,OAAO;AAAA,QACb,mCAAmC,QAAQ,QAAQ;AAAA;AAAA,MACrD;AACA,MAAAA,SAAQ,OAAO,MAAM,gCAAgC,QAAQ,KAAK;AAAA,CAAI;AACtE,MAAAA,SAAQ,OAAO,MAAM,sCAAsC;AAAA,IAC7D;AAEA,UAAM,OAAO,YAAY;AACvB,YAAM,OAAO,KAAK;AAClB,MAAAA,SAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,IAAAA,SAAQ,GAAG,UAAU,MAAM;AACzB,WAAK,KAAK;AAAA,IACZ,CAAC;AACD,IAAAA,SAAQ,GAAG,WAAW,MAAM;AAC1B,WAAK,KAAK;AAAA,IACZ,CAAC;AAED,UAAM,IAAI,QAAc,MAAM;AAAA,IAE9B,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,OAAO,KAAK,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAClC,UAAM;AAAA,EACR;AACF;AAQA,SAAS,UAAU,MAA4B;AAC7C,QAAM,UAAuC,CAAC;AAC9C,QAAM,YAAsB,CAAC;AAC7B,QAAM,aAAuB,CAAC;AAC9B,MAAI,OAAO;AAEX,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACnD,UAAM,MAAM,KAAK,KAAK;AAEtB,YAAQ,KAAK;AAAA,MACX,KAAK,YAAY;AACf,cAAM,QAAQ;AAAA,UACZ;AAAA,UACA,EAAE;AAAA,UACF;AAAA,QACF;AACA,gBAAQ,SAAS;AACjB;AAAA,MACF;AAAA,MACA,KAAK,WAAW;AAEd,kBAAU,MAAM,EAAE,OAAO,GAAG;AAC5B;AAAA,MACF;AAAA,MACA,KAAK,aAAa;AAChB,gBAAQ,UAAU,UAAU,MAAM,EAAE,OAAO,GAAG;AAC9C;AAAA,MACF;AAAA,MACA,KAAK,cAAc;AACjB,gBAAQ,WAAW,UAAU,MAAM,EAAE,OAAO,GAAG;AAC/C;AAAA,MACF;AAAA,MACA,KAAK,cAAc;AACjB,gBAAQ,WAAW,UAAU,MAAM,EAAE,OAAO,GAAG;AAC/C;AAAA,MACF;AAAA,MACA,KAAK,cAAc;AACjB,gBAAQ,WAAW,UAAU,MAAM,EAAE,OAAO,GAAG;AAC/C;AAAA,MACF;AAAA,MACA,KAAK,eAAe;AAClB,mBAAW,KAAK,UAAU,MAAM,EAAE,OAAO,GAAG,CAAC;AAC7C;AAAA,MACF;AAAA,MACA,KAAK,eAAe;AAClB,kBAAU,KAAK,UAAU,MAAM,EAAE,OAAO,GAAG,CAAC;AAC5C;AAAA,MACF;AAAA,MACA,KAAK,UAAU;AACb,eAAO;AACP;AAAA,MACF;AAAA,MACA,KAAK,UAAU;AACb,kBAAU;AACV,QAAAA,SAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,MACA,SAAS;AACP,cAAM,IAAI,MAAM,qBAAqB,GAAG,EAAE;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AAEA,MAAI,WAAW,SAAS,GAAG;AACzB,YAAQ,aAAa;AAAA,EACvB;AAEA,SAAO,EAAE,SAAS,WAAW,KAAK;AACpC;AAEA,SAAS,UAAU,MAAgB,OAAe,MAAsB;AACtE,QAAM,QAAQ,KAAK,KAAK;AACxB,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,qBAAqB,IAAI,EAAE;AAAA,EAC7C;AACA,SAAO;AACT;AAEA,SAAS,YAAkB;AACzB,EAAAA,SAAQ,OAAO,MAAM;AAAA;AAAA,CAA4B;AACjD,EAAAA,SAAQ,OAAO,MAAM;AAAA,CAAY;AACjC,EAAAA,SAAQ,OAAO,MAAM;AAAA,CAAgC;AACrD,EAAAA,SAAQ,OAAO,MAAM;AAAA,CAAqB;AAC1C,EAAAA,SAAQ,OAAO,MAAM;AAAA,CAAmD;AACxE,EAAAA,SAAQ,OAAO,MAAM;AAAA,CAAuB;AAC5C,EAAAA,SAAQ,OAAO,MAAM;AAAA,CAAuB;AAC5C,EAAAA,SAAQ,OAAO,MAAM;AAAA,CAA2B;AAChD,EAAAA,SAAQ,OAAO,MAAM;AAAA,CAAwC;AAC7D,EAAAA,SAAQ,OAAO,MAAM;AAAA,CAAwC;AAC7D,EAAAA,SAAQ,OAAO,MAAM;AAAA,CAAY;AACjC,EAAAA,SAAQ,OAAO,MAAM;AAAA,CAAY;AACnC;AAEA,KAAK,KAAK,EAAE,MAAM,CAAC,UAAmB;AACpC,QAAM,UACJ,iBAAiB,QAAS,MAAM,SAAS,MAAM,UAAW,OAAO,KAAK;AACxE,EAAAA,SAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AACnC,EAAAA,SAAQ,KAAK,CAAC;AAChB,CAAC;","names":["process","fs","os","path","process","cacheLibDir","cacheExtDir","process","fs","path","os","process"]}
package/dist/index.d.ts CHANGED
@@ -3,40 +3,49 @@ import { QueryResultRow, QueryConfig, QueryResult, Client } from 'pg';
3
3
  type PostgresMemoryServerPreset = "postgres" | "paradedb";
4
4
  interface PostgresMemoryServerOptions {
5
5
  /**
6
- * Preset used to choose the default image and default extensions.
6
+ * Preset used to choose default extensions and behavior.
7
7
  * Defaults to "postgres".
8
8
  */
9
9
  preset?: PostgresMemoryServerPreset;
10
10
  /**
11
- * Version or tag to use for the selected preset.
12
- * Examples: "16" for postgres, "0.22.3-pg17" for ParadeDB.
13
- * Ignored when image is provided.
11
+ * Version string for the selected preset.
12
+ *
13
+ * For the "paradedb" preset, this specifies the ParadeDB extension version
14
+ * (e.g., "0.22.5" or "0.22.5-pg17"). The PG suffix, if present, is validated
15
+ * against the installed embedded-postgres version.
16
+ *
17
+ * For the "postgres" preset, this is ignored — the PostgreSQL version is
18
+ * determined by the installed `embedded-postgres` npm package version.
19
+ *
20
+ * Ignored when `image` is provided (Docker fallback).
14
21
  */
15
22
  version?: string;
16
23
  /**
17
- * Container image to start.
18
- * Defaults to postgres:17 for the postgres preset
19
- * and paradedb/paradedb:0.22.3-pg17 for the ParadeDB preset.
20
- * Takes precedence over version when both are provided.
24
+ * @deprecated Docker images are no longer used. This option is ignored.
25
+ * The PostgreSQL version is determined by the `embedded-postgres` npm package.
21
26
  */
22
27
  image?: string;
23
- /** Database name created inside the container. Defaults to testdb. */
28
+ /** Database name created inside the instance. Defaults to "testdb". */
24
29
  database?: string;
25
- /** Username for the test database. Defaults to testuser. */
30
+ /** Username for the test database. Defaults to "testuser". */
26
31
  username?: string;
27
- /** Password for the test database. Defaults to testpassword. */
32
+ /** Password for the test database. Defaults to "testpassword". */
28
33
  password?: string;
29
34
  /**
30
- * Extensions to create after the container starts.
35
+ * Extensions to create after the server starts.
31
36
  * Each entry becomes CREATE EXTENSION IF NOT EXISTS <name>.
37
+ *
38
+ * For the "paradedb" preset, defaults to ["pg_search"].
39
+ * Note: pgvector ("vector") is not bundled — install it separately if needed.
32
40
  */
33
41
  extensions?: string[];
34
- /** Additional SQL statements to run after the container starts. */
42
+ /** Additional SQL statements to run after the server starts. */
35
43
  initSql?: string[];
36
44
  }
37
45
  interface NormalizedPostgresMemoryServerOptions {
38
46
  preset: PostgresMemoryServerPreset;
39
47
  version?: string;
48
+ /** Descriptive label (e.g., "postgres:18" or "paradedb:0.22.5-pg18"). */
40
49
  image: string;
41
50
  database: string;
42
51
  username: string;
@@ -56,10 +65,13 @@ type QueryText<Row extends QueryResultRow = QueryResultRow> = string | QueryConf
56
65
  type QueryResponse<Row extends QueryResultRow = QueryResultRow> = QueryResult<Row>;
57
66
 
58
67
  declare class PostgresMemoryServer {
59
- private readonly container;
68
+ private readonly pg;
69
+ private readonly port;
70
+ private readonly dataDir;
60
71
  private readonly options;
61
72
  private stopped;
62
73
  private readonly snapshotSupported;
74
+ private hasSnapshot;
63
75
  private constructor();
64
76
  static create(options?: PostgresMemoryServerOptions): Promise<PostgresMemoryServer>;
65
77
  static createPostgres(options?: Omit<PostgresMemoryServerOptions, "preset">): Promise<PostgresMemoryServer>;
@@ -71,15 +83,43 @@ declare class PostgresMemoryServer {
71
83
  getUsername(): string;
72
84
  getPassword(): string;
73
85
  getImage(): string;
86
+ /**
87
+ * Returns the absolute path to the temporary PostgreSQL data directory
88
+ * for this instance. Useful for debugging or backing up state. The
89
+ * directory is automatically removed by `stop()`.
90
+ */
91
+ getDataDir(): string;
74
92
  getConnectionOptions(): PostgresConnectionOptions;
75
93
  query<Row extends QueryResultRow = QueryResultRow>(text: QueryText<Row>, params?: QueryParams): Promise<QueryResponse<Row>>;
76
94
  withClient<T>(callback: (client: Client) => Promise<T>): Promise<T>;
77
95
  runSql(sql: string | string[]): Promise<void>;
78
96
  runSqlFile(filePath: string): Promise<void>;
79
97
  runMigrationsDir(dirPath: string): Promise<string[]>;
98
+ /**
99
+ * Create a snapshot of the current database state.
100
+ * Uses PostgreSQL template databases for fast, native snapshots.
101
+ */
80
102
  snapshot(): Promise<void>;
103
+ /**
104
+ * Restore the database to the last snapshot.
105
+ * Drops and recreates the database from the snapshot template.
106
+ */
81
107
  restore(): Promise<void>;
82
108
  stop(): Promise<void>;
109
+ /**
110
+ * Synchronous cleanup for use in process exit handlers. Cannot await,
111
+ * so we just remove the data directory and let the OS reap the postgres
112
+ * child process. embedded-postgres registers its own exit hook to kill
113
+ * the process; this method is a backup for the data directory only.
114
+ *
115
+ * @internal
116
+ */
117
+ _cleanupSync(): void;
118
+ /**
119
+ * Connect to the "postgres" system database for admin operations
120
+ * (snapshot, restore, etc.).
121
+ */
122
+ private withAdminClient;
83
123
  private ensureRunning;
84
124
  private ensureSnapshotSupported;
85
125
  }
@@ -96,12 +136,15 @@ interface JestGlobalTeardownOptions {
96
136
  declare function createJestGlobalSetup(options?: JestGlobalSetupOptions): () => Promise<void>;
97
137
  declare function createJestGlobalTeardown(options?: JestGlobalTeardownOptions): () => Promise<void>;
98
138
 
99
- declare const POSTGRES_IMAGE_REPOSITORY = "postgres";
100
- declare const PARADEDB_IMAGE_REPOSITORY = "paradedb/paradedb";
101
- declare const DEFAULT_POSTGRES_VERSION = "17";
102
- declare const DEFAULT_PARADEDB_VERSION = "0.22.3-pg17";
139
+ declare const DEFAULT_PARADEDB_EXT_VERSION = "0.22.5";
140
+ declare const DEFAULT_POSTGRES_VERSION: string;
141
+ declare const DEFAULT_PARADEDB_VERSION: string;
142
+ /** Descriptive label for the postgres preset. */
103
143
  declare const DEFAULT_POSTGRES_IMAGE: string;
144
+ /** Descriptive label for the paradedb preset. */
104
145
  declare const DEFAULT_PARADEDB_IMAGE: string;
146
+ declare const POSTGRES_IMAGE_REPOSITORY = "postgres";
147
+ declare const PARADEDB_IMAGE_REPOSITORY = "paradedb";
105
148
  declare function normalizeOptions(options?: PostgresMemoryServerOptions): NormalizedPostgresMemoryServerOptions;
106
149
  declare function getImageForVersion(preset: PostgresMemoryServerPreset, version: string): string;
107
150
  declare function getDefaultImage(preset: PostgresMemoryServerPreset): string;
@@ -117,5 +160,8 @@ declare class SnapshotUnsupportedError extends PostgresMemoryServerError {
117
160
  declare class ServerStoppedError extends PostgresMemoryServerError {
118
161
  constructor();
119
162
  }
163
+ declare class ExtensionInstallError extends PostgresMemoryServerError {
164
+ constructor(extensionName: string, cause?: Error);
165
+ }
120
166
 
121
- export { DEFAULT_JEST_ENV_VAR_NAME, DEFAULT_JEST_STATE_FILE, DEFAULT_PARADEDB_IMAGE, DEFAULT_PARADEDB_VERSION, DEFAULT_POSTGRES_IMAGE, DEFAULT_POSTGRES_VERSION, type JestGlobalSetupOptions, type JestGlobalTeardownOptions, type NormalizedPostgresMemoryServerOptions, PARADEDB_IMAGE_REPOSITORY, POSTGRES_IMAGE_REPOSITORY, type PostgresConnectionOptions, PostgresMemoryServer, PostgresMemoryServerError, type PostgresMemoryServerOptions, type PostgresMemoryServerPreset, type QueryResponse, type QueryText, ServerStoppedError, SnapshotUnsupportedError, buildInitStatements, createJestGlobalSetup, createJestGlobalTeardown, getDefaultExtensions, getDefaultImage, getImageForVersion, normalizeOptions };
167
+ export { DEFAULT_JEST_ENV_VAR_NAME, DEFAULT_JEST_STATE_FILE, DEFAULT_PARADEDB_EXT_VERSION, DEFAULT_PARADEDB_IMAGE, DEFAULT_PARADEDB_VERSION, DEFAULT_POSTGRES_IMAGE, DEFAULT_POSTGRES_VERSION, ExtensionInstallError, type JestGlobalSetupOptions, type JestGlobalTeardownOptions, type NormalizedPostgresMemoryServerOptions, PARADEDB_IMAGE_REPOSITORY, POSTGRES_IMAGE_REPOSITORY, type PostgresConnectionOptions, PostgresMemoryServer, PostgresMemoryServerError, type PostgresMemoryServerOptions, type PostgresMemoryServerPreset, type QueryResponse, type QueryText, ServerStoppedError, SnapshotUnsupportedError, buildInitStatements, createJestGlobalSetup, createJestGlobalTeardown, getDefaultExtensions, getDefaultImage, getImageForVersion, normalizeOptions };