pgsqlio 0.2.1 → 0.2.2
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.
|
@@ -191,9 +191,62 @@ import {
|
|
|
191
191
|
BoxRenderable,
|
|
192
192
|
TextRenderable
|
|
193
193
|
} from "@opentui/core";
|
|
194
|
+
|
|
195
|
+
// package.json
|
|
196
|
+
var package_default = {
|
|
197
|
+
name: "pgsqlio",
|
|
198
|
+
version: "0.2.2",
|
|
199
|
+
description: "Interactive PostgreSQL dump, restore, and cleanup CLI (OpenTUI)",
|
|
200
|
+
type: "module",
|
|
201
|
+
bin: {
|
|
202
|
+
pgsqlio: "./dist/bin.js"
|
|
203
|
+
},
|
|
204
|
+
files: [
|
|
205
|
+
"dist"
|
|
206
|
+
],
|
|
207
|
+
scripts: {
|
|
208
|
+
build: "tsup",
|
|
209
|
+
dev: "bun src/cli.ts",
|
|
210
|
+
start: "bun dist/cli.js",
|
|
211
|
+
prepublishOnly: "npm run build"
|
|
212
|
+
},
|
|
213
|
+
engines: {
|
|
214
|
+
bun: ">=1.3.0",
|
|
215
|
+
node: ">=26.4.0"
|
|
216
|
+
},
|
|
217
|
+
keywords: [
|
|
218
|
+
"postgresql",
|
|
219
|
+
"postgres",
|
|
220
|
+
"pg_dump",
|
|
221
|
+
"backup",
|
|
222
|
+
"restore",
|
|
223
|
+
"cli",
|
|
224
|
+
"opentui",
|
|
225
|
+
"tui"
|
|
226
|
+
],
|
|
227
|
+
license: "MIT",
|
|
228
|
+
repository: {
|
|
229
|
+
type: "git",
|
|
230
|
+
url: "git+https://github.com/kingRayhan/pgsqlio.git"
|
|
231
|
+
},
|
|
232
|
+
devDependencies: {
|
|
233
|
+
"@types/node": "^22.20.2",
|
|
234
|
+
tsup: "^8.4.0",
|
|
235
|
+
tsx: "^4.19.3",
|
|
236
|
+
typescript: "^5.8.2"
|
|
237
|
+
},
|
|
238
|
+
dependencies: {
|
|
239
|
+
"@opentui/core": "0.3.4",
|
|
240
|
+
"opentui-spinner": "0.0.7"
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// src/version.ts
|
|
245
|
+
var VERSION = package_default.version;
|
|
246
|
+
|
|
247
|
+
// src/tui/branding.ts
|
|
194
248
|
var SHELL_ID = "app-shell";
|
|
195
249
|
var CONTENT_ID = "app-content";
|
|
196
|
-
var VERSION = "0.1.0";
|
|
197
250
|
function createHeader(renderer) {
|
|
198
251
|
const header = new BoxRenderable(renderer, {
|
|
199
252
|
id: "app-header",
|
|
@@ -1258,4 +1311,4 @@ async function runApp() {
|
|
|
1258
1311
|
export {
|
|
1259
1312
|
runApp
|
|
1260
1313
|
};
|
|
1261
|
-
//# sourceMappingURL=app-
|
|
1314
|
+
//# sourceMappingURL=app-K3XTFTB6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/app.ts","../src/commands/dump.ts","../src/utils.ts","../src/tui/shared.ts","../src/tui/branding.ts","../package.json","../src/version.ts","../src/commands/restore.ts","../src/commands/cleanup.ts","../src/commands/drop-databases.ts"],"sourcesContent":["import { createCliRenderer } from \"@opentui/core\";\nimport { runDumpFlow } from \"./commands/dump.js\";\nimport { runRestoreFlow } from \"./commands/restore.js\";\nimport { runCleanupFlow } from \"./commands/cleanup.js\";\nimport { runDropDatabasesFlow } from \"./commands/drop-databases.js\";\nimport { mountShell } from \"./tui/branding.js\";\nimport { BACK, promptSelect } from \"./tui/shared.js\";\n\nexport async function runApp(): Promise<void> {\n const renderer = await createCliRenderer({\n exitOnCtrlC: true,\n backgroundColor: \"#0C0C0C\",\n });\n\n renderer.start();\n mountShell(renderer);\n\n try {\n while (true) {\n const action = await promptSelect(renderer, {\n title: \"pgsqlio\",\n message: \"What do you want to do?\",\n choices: [\n {\n name: \"Dump\",\n description: \"Backup one or more databases\",\n value: \"dump\",\n },\n {\n name: \"Restore\",\n description: \"Import a .sql backup into a database\",\n value: \"restore\",\n },\n {\n name: \"Cleanup\",\n description: \"Drop and recreate the public schema\",\n value: \"cleanup\",\n },\n {\n name: \"Drop databases\",\n description: \"Select and permanently drop databases\",\n value: \"drop-databases\",\n },\n {\n name: \"Quit\",\n description: \"Exit pgsqlio\",\n value: \"quit\",\n },\n ],\n });\n\n if (action === BACK || action === \"quit\") break;\n\n if (action === \"dump\") await runDumpFlow(renderer);\n else if (action === \"restore\") await runRestoreFlow(renderer);\n else if (action === \"cleanup\") await runCleanupFlow(renderer);\n else if (action === \"drop-databases\")\n await runDropDatabasesFlow(renderer);\n }\n } finally {\n renderer.destroy();\n }\n}\n","import { createWriteStream, unlinkSync, type WriteStream } from \"node:fs\";\nimport { spawn } from \"node:child_process\";\nimport { finished, pipeline } from \"node:stream/promises\";\nimport {\n BoxRenderable,\n TextRenderable,\n type CliRenderer,\n type KeyEvent,\n} from \"@opentui/core\";\nimport { SpinnerRenderable } from \"opentui-spinner\";\nimport { replaceDbInUrl, requireBin, timestamp } from \"../utils.js\";\nimport {\n BACK,\n clearContent,\n promptDbUrlAndDatabases,\n promptMultiSelect,\n promptSelect,\n type FlowResult,\n} from \"../tui/shared.js\";\n\ntype OutputMode = \"separate\" | \"single\";\n\nconst PG_DUMP_ARGS = [\"--clean\", \"--if-exists\"] as const;\n\nfunction quoteIdent(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction sqlString(name: string): string {\n return `'${name.replace(/'/g, \"''\")}'`;\n}\n\nasync function waitExit(child: ReturnType<typeof spawn>): Promise<number | null> {\n if (child.exitCode !== null) return child.exitCode;\n return new Promise((resolve) => child.once(\"close\", resolve));\n}\n\nasync function dumpOne(url: string, outFile: string): Promise<boolean> {\n const child = spawn(\"pg_dump\", [...PG_DUMP_ARGS, url], {\n stdio: [\"ignore\", \"pipe\", \"inherit\"],\n });\n const out = createWriteStream(outFile);\n\n try {\n await pipeline(child.stdout!, out);\n } catch {\n return false;\n }\n\n return (await waitExit(child)) === 0;\n}\n\n/** Append one database dump into an open stream (does not end the stream). */\nasync function dumpAppend(\n url: string,\n out: WriteStream,\n dbName: string,\n): Promise<boolean> {\n // Create DB if missing, then connect — required for restore onto empty servers\n const header =\n `\\n--\\n-- Database: ${dbName}\\n--\\n` +\n `\\\\connect postgres\\n` +\n `SELECT format('CREATE DATABASE %I', ${sqlString(dbName)})\\n` +\n `WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = ${sqlString(dbName)})\\\\gexec\\n` +\n `\\\\connect ${quoteIdent(dbName)}\\n\\n`;\n\n await new Promise<void>((resolve, reject) => {\n out.write(header, (err) => (err ? reject(err) : resolve()));\n });\n\n const child = spawn(\"pg_dump\", [...PG_DUMP_ARGS, url], {\n stdio: [\"ignore\", \"pipe\", \"inherit\"],\n });\n child.stdout!.pipe(out, { end: false });\n\n try {\n await finished(child.stdout!);\n } catch {\n return false;\n }\n\n return (await waitExit(child)) === 0;\n}\n\nasync function runProgress(\n renderer: CliRenderer,\n dbUrl: string,\n selected: string[],\n outputMode: OutputMode,\n): Promise<number> {\n const content = clearContent(renderer);\n\n const ts = timestamp();\n let failed = 0;\n const combinedFile =\n outputMode === \"single\" ? `backup_combined_${ts}.sql` : null;\n\n const panel = new BoxRenderable(renderer, {\n id: \"progress-panel\",\n border: true,\n borderColor: \"#555555\",\n title:\n outputMode === \"single\"\n ? ` dumping ${selected.length} database(s) → one file `\n : ` dumping ${selected.length} database(s) `,\n flexDirection: \"column\",\n padding: 1,\n width: \"100%\",\n flexGrow: 1,\n });\n\n const status = new TextRenderable(renderer, {\n id: \"progress-status\",\n content: combinedFile ? `Writing ${combinedFile}…` : \"Starting…\",\n fg: \"#AAAAAA\",\n marginBottom: 1,\n });\n panel.add(status);\n\n type Row = {\n spinner: SpinnerRenderable;\n label: TextRenderable;\n };\n\n const rows = new Map<string, Row>();\n\n for (const db of selected) {\n const box = new BoxRenderable(renderer, {\n id: `row-${db}`,\n flexDirection: \"row\",\n alignItems: \"center\",\n height: 1,\n width: \"100%\",\n });\n const spinner = new SpinnerRenderable(renderer, {\n id: `spin-${db}`,\n name: \"dots\",\n color: \"#88CCFF\",\n autoplay: false,\n });\n const label = new TextRenderable(renderer, {\n id: `label-${db}`,\n content: ` ${db} pending`,\n fg: \"#888888\",\n marginLeft: 1,\n });\n box.add(spinner);\n box.add(label);\n panel.add(box);\n rows.set(db, { spinner, label });\n }\n\n content.add(panel);\n\n const combined = combinedFile ? createWriteStream(combinedFile) : null;\n if (combined) {\n combined.write(\n `-- pgsqlio combined dump\\n-- databases: ${selected.join(\", \")}\\n-- created: ${ts}\\n`,\n );\n }\n\n for (let i = 0; i < selected.length; i++) {\n const db = selected[i]!;\n const url = replaceDbInUrl(dbUrl, db);\n const row = rows.get(db)!;\n const outLabel = combinedFile ?? `backup_${db}_${ts}.sql`;\n\n status.content = `Dumping ${i + 1}/${selected.length}: ${db}`;\n row.label.content = ` ${db} → ${outLabel}`;\n row.label.fg = \"#FFFFFF\";\n row.spinner.start();\n\n const ok = combined\n ? await dumpAppend(url, combined, db)\n : await dumpOne(url, outLabel);\n\n row.spinner.stop();\n row.spinner.visible = false;\n\n if (ok) {\n row.label.content = `✓ ${db} → ${outLabel}`;\n row.label.fg = \"#66DD88\";\n } else {\n row.label.content = `✗ ${db} failed`;\n row.label.fg = \"#FF6666\";\n failed += 1;\n if (!combined) {\n try {\n unlinkSync(outLabel);\n } catch {\n /* ignore */\n }\n }\n }\n }\n\n if (combined) {\n await new Promise<void>((resolve, reject) => {\n combined.end(() => resolve());\n combined.on(\"error\", reject);\n });\n if (failed > 0) {\n try {\n unlinkSync(combinedFile!);\n } catch {\n /* ignore */\n }\n }\n }\n\n status.content =\n failed === 0\n ? combinedFile\n ? `Done — ${selected.length} database(s) → ${combinedFile}`\n : `Done — ${selected.length} database(s) dumped`\n : `Finished with ${failed} failure(s)`;\n status.fg = failed === 0 ? \"#66DD88\" : \"#FFAA66\";\n\n panel.add(\n new TextRenderable(renderer, {\n id: \"progress-done\",\n content: \"Press Enter to continue\",\n fg: \"#888888\",\n marginTop: 1,\n }),\n );\n\n await new Promise<void>((resolve) => {\n const onKey = (key: KeyEvent) => {\n if (key.name === \"return\" || key.name === \"enter\" || key.name === \"q\") {\n renderer.keyInput.off(\"keypress\", onKey);\n resolve();\n }\n };\n renderer.keyInput.on(\"keypress\", onKey);\n });\n\n return failed;\n}\n\nexport async function runDumpFlow(renderer: CliRenderer): Promise<FlowResult> {\n requireBin(\"psql\");\n requireBin(\"pg_dump\");\n\n let dbUrl: string;\n let databases: string[];\n try {\n const listed = await promptDbUrlAndDatabases(renderer, \"pgsqlio · dump\");\n dbUrl = listed.url;\n databases = listed.databases;\n } catch {\n return \"back\";\n }\n\n let selected: string[] | undefined;\n let outputMode: OutputMode = \"separate\";\n\n while (!selected) {\n const mode = await promptSelect(renderer, {\n title: \"pgsqlio · dump\",\n message: \"What do you want to dump?\",\n allowBack: true,\n choices: [\n {\n name: `All databases (${databases.length})`,\n description: \"Dump every non-template database\",\n value: \"all\",\n },\n {\n name: \"Select databases\",\n description: \"Pick databases with checkboxes\",\n value: \"select\",\n },\n ],\n });\n\n if (mode === BACK) return \"back\";\n\n if (mode === \"all\") {\n selected = [...databases];\n } else {\n const picks = await promptMultiSelect(renderer, {\n title: \"select databases\",\n items: databases,\n });\n if (picks === BACK) continue;\n if (picks.length === 0) continue;\n selected = picks;\n }\n\n if (selected.length > 1) {\n const fileMode = await promptSelect(renderer, {\n title: \"pgsqlio · dump\",\n message: `How should ${selected.length} databases be written?`,\n allowBack: true,\n choices: [\n {\n name: \"Separate files\",\n description: \"One backup_<db>_….sql file per database\",\n value: \"separate\" as const,\n },\n {\n name: \"Single file\",\n description: \"One backup_combined_….sql with \\\\connect between DBs\",\n value: \"single\" as const,\n },\n ],\n });\n\n if (fileMode === BACK) {\n selected = undefined;\n continue;\n }\n outputMode = fileMode;\n } else {\n outputMode = \"separate\";\n }\n }\n\n const failed = await runProgress(renderer, dbUrl, selected, outputMode);\n return failed === 0 ? \"ok\" : \"fail\";\n}\n","import { spawn, spawnSync } from \"node:child_process\";\n\nexport function requireBin(name: string): void {\n const result = spawnSync(name, [\"--version\"], { encoding: \"utf8\" });\n if (result.error || result.status !== 0) {\n console.error(`❌ Missing required binary: ${name} (install PostgreSQL client tools)`);\n process.exit(1);\n }\n}\n\nexport function run(\n cmd: string,\n args: string[],\n options?: { input?: string },\n): { ok: boolean; output: string } {\n const result = spawnSync(cmd, args, {\n encoding: \"utf8\",\n input: options?.input,\n stdio: options?.input !== undefined ? [\"pipe\", \"pipe\", \"pipe\"] : [\"ignore\", \"pipe\", \"pipe\"],\n });\n const output = [result.stdout, result.stderr].filter(Boolean).join(\"\\n\").trim();\n return { ok: result.status === 0, output };\n}\n\nexport function quoteIdent(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\n/** Create database if it does not exist (connect via adminUrl, usually …/postgres). */\nexport function ensureDatabase(adminUrl: string, name: string): { ok: boolean; output: string } {\n const lit = name.replace(/'/g, \"''\");\n const { ok: checkOk, stdout } = runCapture(\"psql\", [\n adminUrl,\n \"-Atc\",\n `SELECT 1 FROM pg_database WHERE datname = '${lit}'`,\n ]);\n if (checkOk && stdout.trim() === \"1\") {\n return { ok: true, output: \"\" };\n }\n return run(\"psql\", [adminUrl, \"-v\", \"ON_ERROR_STOP=1\", \"-c\", `CREATE DATABASE ${quoteIdent(name)}`]);\n}\n\n/** Reset public schema so a plain dump can restore without \"already exists\" errors. */\nexport function wipePublicSchema(dbUrl: string): { ok: boolean; output: string } {\n return run(\"psql\", [\n dbUrl,\n \"-v\",\n \"ON_ERROR_STOP=1\",\n \"-c\",\n \"DROP SCHEMA IF EXISTS public CASCADE; CREATE SCHEMA public; GRANT ALL ON SCHEMA public TO public; GRANT ALL ON SCHEMA public TO CURRENT_USER;\",\n ]);\n}\n\n/** Parse \\\\connect targets from a dump (for combined backups). */\nexport function extractConnectTargets(sql: string): string[] {\n const found = new Set<string>();\n for (const m of sql.matchAll(/\\\\connect\\s+\"((?:\\\\.|[^\"\\\\])*)\"/gi)) {\n found.add(m[1]!.replace(/\"\"/g, '\"'));\n }\n for (const m of sql.matchAll(/\\\\connect\\s+([^\\s\"]+)/gi)) {\n const name = m[1]!.replace(/;$/, \"\");\n if (name.toLowerCase() !== \"postgres\") found.add(name);\n }\n found.delete(\"postgres\");\n return [...found];\n}\n\nexport function runCapture(\n cmd: string,\n args: string[],\n): { ok: boolean; stdout: string; stderr: string } {\n const result = spawnSync(cmd, args, { encoding: \"utf8\" });\n return {\n ok: result.status === 0,\n stdout: (result.stdout ?? \"\").trim(),\n stderr: (result.stderr ?? \"\").trim(),\n };\n}\n\nexport function runCaptureAsync(\n cmd: string,\n args: string[],\n): Promise<{ ok: boolean; stdout: string; stderr: string }> {\n return new Promise((resolve) => {\n const child = spawn(cmd, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n const out: Buffer[] = [];\n const err: Buffer[] = [];\n child.stdout.on(\"data\", (chunk: Buffer) => out.push(chunk));\n child.stderr.on(\"data\", (chunk: Buffer) => err.push(chunk));\n child.on(\"error\", (error) => {\n resolve({ ok: false, stdout: \"\", stderr: error.message });\n });\n child.on(\"close\", (code) => {\n resolve({\n ok: code === 0,\n stdout: Buffer.concat(out).toString(\"utf8\").trim(),\n stderr: Buffer.concat(err).toString(\"utf8\").trim(),\n });\n });\n });\n}\n\n/** Ensure URL has a database path (defaults to postgres). */\nexport function normalizeConnUrl(url: string): string {\n const [base, query] = url.split(\"?\");\n let next = base ?? url;\n if (/^postgres(?:ql)?:\\/\\/[^/]+$/i.test(next)) {\n next = `${next}/postgres`;\n } else if (/^postgres(?:ql)?:\\/\\/[^/]+\\/$/i.test(next)) {\n next = `${next}postgres`;\n }\n return query !== undefined ? `${next}?${query}` : next;\n}\n\nexport function replaceDbInUrl(url: string, newDb: string): string {\n const normalized = normalizeConnUrl(url);\n const [base, query] = normalized.split(\"?\");\n const match = (base ?? normalized).match(/^(postgres(?:ql)?:\\/\\/[^/]+)/i);\n const authority = match?.[1] ?? (base ?? normalized).replace(/\\/[^/]*$/, \"\");\n const replaced = `${authority}/${newDb}`;\n return query !== undefined ? `${replaced}?${query}` : replaced;\n}\n\nexport function timestamp(): string {\n const d = new Date();\n const pad = (n: number) => String(n).padStart(2, \"0\");\n return (\n `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}_` +\n `${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`\n );\n}\n\nexport async function pingConnection(\n dbUrl: string,\n): Promise<{ ok: boolean; error?: string }> {\n const url = normalizeConnUrl(dbUrl);\n const { ok, stdout, stderr } = await runCaptureAsync(\"psql\", [\n url,\n \"-Atc\",\n \"SELECT 1\",\n ]);\n if (!ok) {\n return { ok: false, error: stderr || stdout || \"Connection failed\" };\n }\n return { ok: true };\n}\n\nexport async function listDatabases(\n dbUrl: string,\n): Promise<{ ok: boolean; databases: string[]; error?: string }> {\n const url = normalizeConnUrl(dbUrl);\n const { ok, stdout, stderr } = await runCaptureAsync(\"psql\", [\n url,\n \"-Atc\",\n \"SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname;\",\n ]);\n if (!ok) {\n return { ok: false, databases: [], error: stderr || stdout || \"Connection failed\" };\n }\n return { ok: true, databases: stdout.split(\"\\n\").filter(Boolean) };\n}\n\nexport function listTables(\n dbUrl: string,\n schema = \"public\",\n): { ok: boolean; tables: string[]; error?: string } {\n const url = normalizeConnUrl(dbUrl);\n const lit = schema.replace(/'/g, \"''\");\n const { ok, stdout, stderr } = runCapture(\"psql\", [\n url,\n \"-Atc\",\n `SELECT tablename FROM pg_tables WHERE schemaname = '${lit}' ORDER BY tablename;`,\n ]);\n if (!ok) {\n return { ok: false, tables: [], error: stderr || stdout || \"Connection failed\" };\n }\n return { ok: true, tables: stdout.split(\"\\n\").filter(Boolean) };\n}\n\nexport function dropTables(\n dbUrl: string,\n tables: string[],\n schema = \"public\",\n): { ok: boolean; output: string } {\n if (tables.length === 0) return { ok: true, output: \"\" };\n const qualified = tables\n .map((t) => `${quoteIdent(schema)}.${quoteIdent(t)}`)\n .join(\", \");\n return run(\"psql\", [\n dbUrl,\n \"-v\",\n \"ON_ERROR_STOP=1\",\n \"-c\",\n `DROP TABLE IF EXISTS ${qualified} CASCADE;`,\n ]);\n}\n\n/** Drop databases (connects via /postgres). Terminates backends when possible. */\nexport function dropDatabases(\n connUrl: string,\n names: string[],\n): { ok: boolean; output: string } {\n const adminUrl = replaceDbInUrl(normalizeConnUrl(connUrl), \"postgres\");\n const logs: string[] = [];\n\n for (const name of names) {\n if (name === \"postgres\" || name.startsWith(\"template\")) {\n return {\n ok: false,\n output: `Refusing to drop protected database: ${name}`,\n };\n }\n\n const lit = name.replace(/'/g, \"''\");\n // Kick connections so DROP DATABASE can proceed\n const terminate = run(\"psql\", [\n adminUrl,\n \"-c\",\n `SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '${lit}' AND pid <> pg_backend_pid();`,\n ]);\n if (terminate.output) logs.push(terminate.output);\n\n const dropped = run(\"psql\", [\n adminUrl,\n \"-v\",\n \"ON_ERROR_STOP=1\",\n \"-c\",\n `DROP DATABASE IF EXISTS ${quoteIdent(name)};`,\n ]);\n if (dropped.output) logs.push(dropped.output);\n if (!dropped.ok) {\n return {\n ok: false,\n output: [`Failed dropping \"${name}\"`, ...logs].filter(Boolean).join(\"\\n\"),\n };\n }\n }\n\n return { ok: true, output: logs.join(\"\\n\").trim() };\n}\n\nexport function printUsage(bin = \"pgsqlio\"): void {\n console.log(`Usage:\n ${bin}\n\nInteractive menu: Dump · Restore · Cleanup · Drop databases`);\n}\n","import {\n BoxRenderable,\n InputRenderable,\n InputRenderableEvents,\n SelectRenderable,\n SelectRenderableEvents,\n TextRenderable,\n type CliRenderer,\n type KeyEvent,\n type SelectOption,\n} from \"@opentui/core\";\nimport { SpinnerRenderable } from \"opentui-spinner\";\nimport { getContent } from \"./branding.js\";\nimport { listDatabases, normalizeConnUrl, pingConnection } from \"../utils.js\";\n\nexport type FlowResult = \"ok\" | \"fail\" | \"back\";\nexport const BACK = \"__back__\" as const;\n\n/** Clear only the content region — sticky branding stays. */\nexport function clearContent(renderer: CliRenderer): BoxRenderable {\n const content = getContent(renderer);\n for (const child of content.getChildren()) {\n content.remove(child.id);\n }\n return content;\n}\n\n/** @deprecated use clearContent — kept as alias for call sites */\nexport const clearRoot = clearContent;\n\nexport function looksLikePgUrl(value: string): boolean {\n return /^(postgres(ql)?:\\/\\/)/i.test(value.trim());\n}\n\n/** Checkbox multi-select with ← Back. Returns BACK or selected item ids. */\nexport function promptMultiSelect(\n renderer: CliRenderer,\n options: {\n title: string;\n items: string[];\n emptyMessage?: string;\n },\n): Promise<string[] | typeof BACK> {\n return new Promise((resolve) => {\n const { items } = options;\n if (items.length === 0) {\n resolve([]);\n return;\n }\n\n const content = clearContent(renderer);\n const choices = [BACK, ...items];\n const checked = new Set<string>();\n let cursor = 1;\n\n const panel = new BoxRenderable(renderer, {\n id: \"pick-panel\",\n border: true,\n borderColor: \"#555555\",\n title: ` ${options.title} `,\n flexDirection: \"column\",\n padding: 1,\n width: \"100%\",\n flexGrow: 1,\n });\n\n panel.add(\n new TextRenderable(renderer, {\n id: \"pick-hint\",\n content: \"Space toggle · a all · Enter confirm · Esc back\",\n fg: \"#888888\",\n marginBottom: 1,\n }),\n );\n\n const list = new BoxRenderable(renderer, {\n id: \"pick-list\",\n flexDirection: \"column\",\n flexGrow: 1,\n width: \"100%\",\n });\n\n const lines: TextRenderable[] = choices.map((_, i) => {\n const line = new TextRenderable(renderer, {\n id: `pick-line-${i}`,\n content: \"\",\n fg: \"#CCCCCC\",\n });\n list.add(line);\n return line;\n });\n\n panel.add(list);\n content.add(panel);\n\n const redraw = () => {\n for (let i = 0; i < choices.length; i++) {\n const id = choices[i]!;\n const isBack = id === BACK;\n const marker = isBack ? \" \" : checked.has(id) ? \"[x]\" : \"[ ]\";\n const pointer = i === cursor ? \"▶\" : \" \";\n const label = isBack ? \"← Back\" : id;\n lines[i]!.content = `${pointer} ${marker} ${label}`;\n lines[i]!.fg = i === cursor ? \"#FFFF66\" : isBack ? \"#88AADD\" : \"#CCCCCC\";\n }\n };\n\n redraw();\n\n const onKey = (key: KeyEvent) => {\n if (key.name === \"up\" || key.name === \"k\") {\n cursor = Math.max(0, cursor - 1);\n redraw();\n return;\n }\n if (key.name === \"down\" || key.name === \"j\") {\n cursor = Math.min(choices.length - 1, cursor + 1);\n redraw();\n return;\n }\n if (key.name === \"space\") {\n const id = choices[cursor]!;\n if (id === BACK) {\n cleanup();\n resolve(BACK);\n return;\n }\n if (checked.has(id)) checked.delete(id);\n else checked.add(id);\n redraw();\n return;\n }\n if (key.name === \"a\") {\n if (checked.size === items.length) checked.clear();\n else items.forEach((item) => checked.add(item));\n redraw();\n return;\n }\n if (key.name === \"escape\") {\n cleanup();\n resolve(BACK);\n return;\n }\n if (key.name === \"return\" || key.name === \"enter\") {\n const id = choices[cursor]!;\n if (id === BACK) {\n cleanup();\n resolve(BACK);\n return;\n }\n if (checked.size === 0) return;\n cleanup();\n resolve([...checked]);\n }\n };\n\n const cleanup = () => {\n renderer.keyInput.off(\"keypress\", onKey);\n };\n\n renderer.keyInput.on(\"keypress\", onKey);\n });\n}\n\nexport function promptSelect<T extends string>(\n renderer: CliRenderer,\n options: {\n title: string;\n message: string;\n hint?: string;\n choices: Array<{ name: string; description: string; value: T }>;\n allowBack?: boolean;\n },\n): Promise<T | typeof BACK> {\n return new Promise((resolve, reject) => {\n const content = clearContent(renderer);\n\n const panel = new BoxRenderable(renderer, {\n id: \"select-panel\",\n border: true,\n borderColor: \"#555555\",\n title: ` ${options.title} `,\n flexDirection: \"column\",\n padding: 1,\n width: \"100%\",\n flexGrow: 1,\n });\n\n panel.add(\n new TextRenderable(renderer, {\n id: \"select-message\",\n content: options.message,\n fg: \"#FFFFFF\",\n marginBottom: 1,\n }),\n );\n\n const menu = new SelectRenderable(renderer, {\n id: \"select-menu\",\n width: \"100%\",\n height: Math.max(4, options.choices.length * 2 + 1),\n showDescription: true,\n showScrollIndicator: false,\n options: options.choices.map(\n (c): SelectOption => ({\n name: c.name,\n description: c.description,\n value: c.value,\n }),\n ),\n });\n\n panel.add(menu);\n panel.add(\n new TextRenderable(renderer, {\n id: \"select-hint\",\n content:\n options.hint ??\n (options.allowBack\n ? \"↑/↓ move · Enter confirm · Esc back\"\n : \"↑/↓ move · Enter confirm · Ctrl+C quit\"),\n fg: \"#888888\",\n marginTop: 1,\n }),\n );\n\n content.add(panel);\n menu.focus();\n\n const onSelect = (_index: number, option: SelectOption) => {\n cleanup();\n resolve(option.value as T);\n };\n\n const onKey = (key: KeyEvent) => {\n if (key.name === \"escape\") {\n cleanup();\n if (options.allowBack) resolve(BACK);\n else reject(new Error(\"cancelled\"));\n }\n };\n\n const cleanup = () => {\n menu.off(SelectRenderableEvents.ITEM_SELECTED, onSelect);\n renderer.keyInput.off(\"keypress\", onKey);\n };\n\n menu.on(SelectRenderableEvents.ITEM_SELECTED, onSelect);\n renderer.keyInput.on(\"keypress\", onKey);\n });\n}\n\nfunction yieldFrame(): Promise<void> {\n return new Promise((resolve) => setImmediate(resolve));\n}\n\nexport function promptText(\n renderer: CliRenderer,\n options: {\n title: string;\n label: string;\n placeholder?: string;\n initial?: string;\n hint?: string;\n maxLength?: number;\n busyMessage?: string;\n validate?: (value: string) => string | null;\n verify?: (value: string) => Promise<string | null>;\n },\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const content = clearContent(renderer);\n\n const panel = new BoxRenderable(renderer, {\n id: \"text-panel\",\n border: true,\n borderColor: \"#555555\",\n title: ` ${options.title} `,\n flexDirection: \"column\",\n padding: 1,\n width: \"100%\",\n flexGrow: 1,\n gap: 1,\n });\n\n panel.add(\n new TextRenderable(renderer, {\n id: \"text-label\",\n content: options.label,\n fg: \"#FFFFFF\",\n }),\n );\n\n const inputFrame = new BoxRenderable(renderer, {\n id: \"text-input-frame\",\n width: \"100%\",\n padding: 1,\n backgroundColor: \"#2A2A2A\",\n });\n\n const input = new InputRenderable(renderer, {\n id: \"text-input\",\n width: \"100%\",\n placeholder: options.placeholder ?? \"\",\n value: options.initial?.trim() ?? \"\",\n maxLength: options.maxLength ?? 2000,\n backgroundColor: \"#2A2A2A\",\n focusedBackgroundColor: \"#2A2A2A\",\n textColor: \"#FFFFFF\",\n cursorColor: \"#88CCFF\",\n });\n\n inputFrame.add(input);\n\n const statusRow = new BoxRenderable(renderer, {\n id: \"text-status-row\",\n flexDirection: \"row\",\n alignItems: \"center\",\n width: \"100%\",\n height: 1,\n });\n const spin = new SpinnerRenderable(renderer, {\n name: \"dots\",\n color: \"#88CCFF\",\n autoplay: false,\n });\n spin.visible = false;\n const statusText = new TextRenderable(renderer, {\n id: \"text-status\",\n content: \"\",\n fg: \"#FF6666\",\n marginLeft: 1,\n });\n statusRow.add(spin);\n statusRow.add(statusText);\n\n panel.add(inputFrame);\n panel.add(statusRow);\n panel.add(\n new TextRenderable(renderer, {\n id: \"text-hint\",\n content: options.hint ?? \"Enter confirm · Esc back\",\n fg: \"#888888\",\n }),\n );\n\n content.add(panel);\n input.focus();\n\n let busy = false;\n let cancelled = false;\n\n const setBusy = (on: boolean, message = \"\") => {\n busy = on;\n if (on) {\n spin.visible = true;\n spin.start();\n statusText.content = message;\n statusText.fg = \"#CCCCCC\";\n } else {\n spin.stop();\n spin.visible = false;\n statusText.content = \"\";\n }\n };\n\n const setError = (msg: string) => {\n spin.stop();\n spin.visible = false;\n busy = false;\n statusText.content = msg;\n statusText.fg = \"#FF6666\";\n input.focus();\n };\n\n const submit = async (value: string) => {\n if (busy) return;\n const trimmed = value.trim();\n if (!trimmed) {\n setError(\"Value is required\");\n return;\n }\n if (options.validate) {\n const msg = options.validate(trimmed);\n if (msg) {\n setError(msg);\n return;\n }\n }\n if (options.verify) {\n setBusy(true, options.busyMessage ?? \"Working…\");\n input.blur();\n await yieldFrame();\n try {\n const msg = await options.verify(trimmed);\n if (cancelled) return;\n if (msg) {\n setError(msg);\n return;\n }\n } catch (err) {\n if (cancelled) return;\n setError(err instanceof Error ? err.message : \"Failed\");\n return;\n }\n if (cancelled) return;\n setBusy(false);\n }\n cleanup();\n resolve(trimmed);\n };\n\n const onEnter = (value: string) => {\n void submit(value);\n };\n const onKey = (key: KeyEvent) => {\n if (key.name === \"escape\") {\n cleanup();\n reject(new Error(\"cancelled\"));\n }\n };\n\n const cleanup = () => {\n cancelled = true;\n busy = false;\n spin.stop();\n input.off(InputRenderableEvents.ENTER, onEnter);\n renderer.keyInput.off(\"keypress\", onKey);\n };\n\n input.on(InputRenderableEvents.ENTER, onEnter);\n renderer.keyInput.on(\"keypress\", onKey);\n });\n}\n\nexport function promptDbUrl(\n renderer: CliRenderer,\n title: string,\n options?: {\n initial?: string;\n busyMessage?: string;\n verify?: (url: string) => Promise<string | null>;\n },\n): Promise<string> {\n const verify =\n options?.verify ??\n (async (url: string) => {\n const ping = await pingConnection(url);\n return ping.ok ? null : ping.error ?? \"Connection failed\";\n });\n\n return promptText(renderer, {\n title,\n label: \"PostgreSQL connection URL\",\n placeholder: \"postgresql://user:password@host:5432\",\n initial: options?.initial,\n hint: \"Enter confirm · Esc back · database name optional (you can pick next)\",\n busyMessage: options?.busyMessage ?? \"Connecting…\",\n validate: (value) =>\n looksLikePgUrl(value)\n ? null\n : \"URL must start with postgresql:// or postgres://\",\n verify: (value) => verify(normalizeConnUrl(value)),\n }).then(normalizeConnUrl);\n}\n\n/** Prompt for a URL and fetch the database list on the same screen. */\nexport async function promptDbUrlAndDatabases(\n renderer: CliRenderer,\n title: string,\n options?: {\n initial?: string;\n emptyMessage?: string;\n filter?: (name: string) => boolean;\n },\n): Promise<{ url: string; databases: string[] }> {\n let databases: string[] = [];\n const url = await promptDbUrl(renderer, title, {\n initial: options?.initial,\n busyMessage: \"Fetching databases…\",\n verify: async (value) => {\n const listed = await listDatabases(value);\n if (!listed.ok) return listed.error ?? \"Connection failed\";\n const next = options?.filter\n ? listed.databases.filter(options.filter)\n : listed.databases;\n if (next.length === 0) {\n return options?.emptyMessage ?? \"No databases found\";\n }\n databases = next;\n return null;\n },\n });\n return { url, databases };\n}\n\nexport async function waitForEnter(\n renderer: CliRenderer,\n message = \"Press Enter to continue\",\n): Promise<void> {\n const content = getContent(renderer);\n const hint = new TextRenderable(renderer, {\n id: `wait-enter-${Date.now()}`,\n content: message,\n fg: \"#888888\",\n marginTop: 1,\n });\n\n const children = content.getChildren();\n const last = children[children.length - 1];\n if (last) {\n try {\n (last as BoxRenderable).add(hint);\n } catch {\n content.add(hint);\n }\n } else {\n content.add(hint);\n }\n\n await new Promise<void>((resolve) => {\n const onKey = (key: KeyEvent) => {\n if (key.name === \"return\" || key.name === \"enter\" || key.name === \"q\") {\n renderer.keyInput.off(\"keypress\", onKey);\n resolve();\n }\n };\n renderer.keyInput.on(\"keypress\", onKey);\n });\n}\n\nexport async function showStatus(\n renderer: CliRenderer,\n options: {\n title: string;\n message: string;\n ok: boolean;\n detail?: string;\n },\n): Promise<void> {\n const content = clearContent(renderer);\n const panel = new BoxRenderable(renderer, {\n id: \"status-panel\",\n border: true,\n borderColor: \"#555555\",\n title: ` ${options.title} `,\n flexDirection: \"column\",\n padding: 1,\n width: \"100%\",\n flexGrow: 1,\n });\n panel.add(\n new TextRenderable(renderer, {\n content: options.message,\n fg: options.ok ? \"#66DD88\" : \"#FF6666\",\n marginBottom: options.detail ? 1 : 0,\n }),\n );\n if (options.detail) {\n const lines = options.detail.split(\"\\n\").filter(Boolean).slice(-8);\n for (const [i, line] of lines.entries()) {\n panel.add(\n new TextRenderable(renderer, {\n id: `status-detail-${i}`,\n content: line.length > 100 ? `${line.slice(0, 97)}…` : line,\n fg: \"#A1A1AA\",\n }),\n );\n }\n }\n content.add(panel);\n await waitForEnter(renderer);\n}\n\nexport async function withSpinner<T>(\n renderer: CliRenderer,\n title: string,\n label: string,\n work: () => Promise<T> | T,\n): Promise<T> {\n const content = clearContent(renderer);\n const panel = new BoxRenderable(renderer, {\n id: \"spinner-panel\",\n border: true,\n borderColor: \"#555555\",\n title: ` ${title} `,\n flexDirection: \"row\",\n alignItems: \"center\",\n padding: 1,\n width: \"100%\",\n flexGrow: 1,\n });\n const spin = new SpinnerRenderable(renderer, {\n id: \"work-spin\",\n name: \"dots\",\n color: \"#88CCFF\",\n });\n panel.add(spin);\n panel.add(\n new TextRenderable(renderer, {\n content: ` ${label}`,\n fg: \"#CCCCCC\",\n marginLeft: 1,\n }),\n );\n content.add(panel);\n await yieldFrame();\n try {\n return await work();\n } finally {\n spin.stop();\n }\n}\n","import {\n ASCIIFontRenderable,\n BoxRenderable,\n TextRenderable,\n type CliRenderer,\n} from \"@opentui/core\";\nimport { VERSION } from \"../version.js\";\n\nexport const SHELL_ID = \"app-shell\";\nexport const CONTENT_ID = \"app-content\";\n\nfunction createHeader(renderer: CliRenderer): BoxRenderable {\n const header = new BoxRenderable(renderer, {\n id: \"app-header\",\n width: \"100%\",\n flexDirection: \"column\",\n flexShrink: 0,\n });\n\n const logo = new BoxRenderable(renderer, {\n id: \"branding-logo\",\n position: \"relative\",\n marginBottom: 0,\n });\n\n logo.add(\n new ASCIIFontRenderable(renderer, {\n id: \"branding-shadow\",\n text: \"pgsqlio\",\n font: \"block\",\n color: \"#1A2228\",\n position: \"absolute\",\n left: 1,\n top: 1,\n zIndex: 0,\n }),\n );\n\n logo.add(\n new ASCIIFontRenderable(renderer, {\n id: \"branding-wordmark\",\n text: \"pgsqlio\",\n font: \"block\",\n color: [\"#2DD4BF\", \"#67E8F9\", \"#E0F2FE\"],\n zIndex: 1,\n }),\n );\n\n header.add(logo);\n header.add(\n new TextRenderable(renderer, {\n id: \"branding-tagline\",\n content: `PostgreSQL dump · restore · cleanup · v${VERSION}`,\n fg: \"#3F3F46\",\n marginTop: 1,\n }),\n );\n\n return header;\n}\n\n/** Mount sticky branding + content region. Call once at app start. */\nexport function mountShell(renderer: CliRenderer): BoxRenderable {\n for (const child of renderer.root.getChildren()) {\n renderer.root.remove(child.id);\n }\n\n const shell = new BoxRenderable(renderer, {\n id: SHELL_ID,\n width: \"100%\",\n height: \"100%\",\n flexDirection: \"column\",\n backgroundColor: \"#0C0C0C\",\n padding: 1,\n });\n\n shell.add(createHeader(renderer));\n\n const content = new BoxRenderable(renderer, {\n id: CONTENT_ID,\n width: \"100%\",\n flexGrow: 1,\n flexShrink: 1,\n flexDirection: \"column\",\n marginTop: 1,\n });\n shell.add(content);\n renderer.root.add(shell);\n return content;\n}\n\nexport function getContent(renderer: CliRenderer): BoxRenderable {\n const shell = renderer.root.getChildren().find((c) => c.id === SHELL_ID) as\n | BoxRenderable\n | undefined;\n if (!shell) {\n return mountShell(renderer);\n }\n const content = shell.getChildren().find((c) => c.id === CONTENT_ID) as\n | BoxRenderable\n | undefined;\n if (!content) {\n return mountShell(renderer);\n }\n return content;\n}\n","{\n \"name\": \"pgsqlio\",\n \"version\": \"0.2.2\",\n \"description\": \"Interactive PostgreSQL dump, restore, and cleanup CLI (OpenTUI)\",\n \"type\": \"module\",\n \"bin\": {\n \"pgsqlio\": \"./dist/bin.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"bun src/cli.ts\",\n \"start\": \"bun dist/cli.js\",\n \"prepublishOnly\": \"npm run build\"\n },\n \"engines\": {\n \"bun\": \">=1.3.0\",\n \"node\": \">=26.4.0\"\n },\n \"keywords\": [\n \"postgresql\",\n \"postgres\",\n \"pg_dump\",\n \"backup\",\n \"restore\",\n \"cli\",\n \"opentui\",\n \"tui\"\n ],\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/kingRayhan/pgsqlio.git\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^22.20.2\",\n \"tsup\": \"^8.4.0\",\n \"tsx\": \"^4.19.3\",\n \"typescript\": \"^5.8.2\"\n },\n \"dependencies\": {\n \"@opentui/core\": \"0.3.4\",\n \"opentui-spinner\": \"0.0.7\"\n }\n}\n","import pkg from \"../package.json\" with { type: \"json\" };\n\nexport const VERSION: string = pkg.version;\n","import { existsSync, readFileSync } from \"node:fs\";\nimport type { CliRenderer } from \"@opentui/core\";\nimport {\n ensureDatabase,\n extractConnectTargets,\n replaceDbInUrl,\n requireBin,\n run,\n wipePublicSchema,\n} from \"../utils.js\";\nimport {\n promptDbUrl,\n promptSelect,\n promptText,\n showStatus,\n withSpinner,\n BACK,\n type FlowResult,\n} from \"../tui/shared.js\";\n\nexport async function runRestoreFlow(renderer: CliRenderer): Promise<FlowResult> {\n requireBin(\"psql\");\n\n let dbUrl: string;\n try {\n dbUrl = await promptDbUrl(renderer, \"pgsqlio · restore\");\n } catch {\n return \"back\";\n }\n\n let file: string;\n try {\n file = await promptText(renderer, {\n title: \"pgsqlio · restore\",\n label: \"SQL backup file path\",\n placeholder: \"backup_mydb_20250924_121530.sql\",\n validate: (value) =>\n existsSync(value) ? null : \"File not found — check the path\",\n });\n } catch {\n return \"back\";\n }\n\n let sql = \"\";\n try {\n sql = readFileSync(file, \"utf8\");\n } catch {\n await showStatus(renderer, {\n title: \"pgsqlio · restore\",\n message: \"❌ Could not read backup file\",\n ok: false,\n });\n return \"fail\";\n }\n\n const targets = extractConnectTargets(sql);\n const isCombined = targets.length > 0;\n const adminUrl = replaceDbInUrl(dbUrl, \"postgres\");\n\n const confirm = await promptSelect(renderer, {\n title: \"pgsqlio · restore\",\n message: isCombined\n ? `Restore ${targets.length} database(s) from ${file}?`\n : `Restore into this database from ${file}?`,\n allowBack: true,\n choices: [\n {\n name: \"Wipe schemas, then restore\",\n description:\n \"DROP SCHEMA public CASCADE on target DB(s) first (fixes “already exists”)\",\n value: \"wipe\",\n },\n {\n name: \"Restore as-is\",\n description: \"Do not wipe — fails if objects already exist\",\n value: \"asis\",\n },\n { name: \"Cancel\", description: \"Return to main menu\", value: \"no\" },\n ],\n });\n\n if (confirm === BACK || confirm === \"no\") return \"back\";\n const wipeFirst = confirm === \"wipe\";\n\n const result = await withSpinner(\n renderer,\n \"pgsqlio · restore\",\n wipeFirst ? \"Wiping + restoring…\" : \"Restoring…\",\n () => {\n const logs: string[] = [];\n\n if (isCombined) {\n for (const db of targets) {\n const created = ensureDatabase(adminUrl, db);\n if (!created.ok) {\n return {\n ok: false,\n output: [`Failed creating database \"${db}\"`, created.output]\n .filter(Boolean)\n .join(\"\\n\"),\n };\n }\n if (created.output) logs.push(created.output);\n\n if (wipeFirst) {\n const wiped = wipePublicSchema(replaceDbInUrl(adminUrl, db));\n if (!wiped.ok) {\n return {\n ok: false,\n output: [`Failed wiping database \"${db}\"`, wiped.output]\n .filter(Boolean)\n .join(\"\\n\"),\n };\n }\n if (wiped.output) logs.push(wiped.output);\n }\n }\n } else if (wipeFirst) {\n const wiped = wipePublicSchema(dbUrl);\n if (!wiped.ok) {\n return {\n ok: false,\n output: [\"Failed wiping target database\", wiped.output]\n .filter(Boolean)\n .join(\"\\n\"),\n };\n }\n if (wiped.output) logs.push(wiped.output);\n }\n\n // Combined dumps switch DB via \\\\connect — start on postgres so meta-commands work\n const restoreUrl = isCombined ? adminUrl : dbUrl;\n const restored = run(\"psql\", [\n restoreUrl,\n \"-v\",\n \"ON_ERROR_STOP=1\",\n \"-f\",\n file,\n ]);\n if (restored.output) logs.push(restored.output);\n return {\n ok: restored.ok,\n output: logs.join(\"\\n\").trim(),\n };\n },\n );\n\n await showStatus(renderer, {\n title: \"pgsqlio · restore\",\n message: result.ok ? \"✅ Restore successful\" : \"❌ Restore failed\",\n ok: result.ok,\n detail: result.ok ? undefined : result.output || undefined,\n });\n\n return result.ok ? \"ok\" : \"fail\";\n}\n","import type { CliRenderer } from \"@opentui/core\";\nimport { requireBin, run } from \"../utils.js\";\nimport {\n BACK,\n promptDbUrl,\n promptSelect,\n showStatus,\n withSpinner,\n type FlowResult,\n} from \"../tui/shared.js\";\n\nexport async function runCleanupFlow(renderer: CliRenderer): Promise<FlowResult> {\n requireBin(\"psql\");\n\n let dbUrl: string;\n try {\n dbUrl = await promptDbUrl(renderer, \"pgsqlio · cleanup\");\n } catch {\n return \"back\";\n }\n\n const confirm = await promptSelect(renderer, {\n title: \"pgsqlio · cleanup\",\n message: \"Drop and recreate the public schema? This is destructive.\",\n allowBack: true,\n choices: [\n {\n name: \"Yes, clean database\",\n description: \"DROP SCHEMA public CASCADE; CREATE SCHEMA public;\",\n value: \"yes\",\n },\n { name: \"Cancel\", description: \"Return to main menu\", value: \"no\" },\n ],\n });\n\n if (confirm === BACK || confirm === \"no\") return \"back\";\n\n const result = await withSpinner(renderer, \"pgsqlio · cleanup\", \"Cleaning…\", () =>\n run(\"psql\", [\n dbUrl,\n \"-v\",\n \"ON_ERROR_STOP=1\",\n \"-c\",\n \"DROP SCHEMA public CASCADE; CREATE SCHEMA public;\",\n ]),\n );\n\n await showStatus(renderer, {\n title: \"pgsqlio · cleanup\",\n message: result.ok\n ? \"✅ Cleanup successful (database is empty)\"\n : \"❌ Cleanup failed\",\n ok: result.ok,\n detail: result.ok ? undefined : result.output || undefined,\n });\n\n return result.ok ? \"ok\" : \"fail\";\n}\n","import type { CliRenderer } from \"@opentui/core\";\nimport { dropDatabases, requireBin } from \"../utils.js\";\nimport {\n BACK,\n promptDbUrlAndDatabases,\n promptMultiSelect,\n promptSelect,\n showStatus,\n withSpinner,\n type FlowResult,\n} from \"../tui/shared.js\";\n\nexport async function runDropDatabasesFlow(\n renderer: CliRenderer,\n): Promise<FlowResult> {\n requireBin(\"psql\");\n\n let connUrl: string;\n let droppable: string[];\n try {\n const listed = await promptDbUrlAndDatabases(\n renderer,\n \"pgsqlio · drop databases\",\n {\n filter: (name) => name !== \"postgres\" && !name.startsWith(\"template\"),\n emptyMessage:\n \"No droppable databases found (postgres / template* are protected)\",\n },\n );\n connUrl = listed.url;\n droppable = listed.databases;\n } catch {\n return \"back\";\n }\n\n const selected = await promptMultiSelect(renderer, {\n title: \"select databases to drop\",\n items: droppable,\n });\n\n if (selected === BACK) return \"back\";\n if (selected.length === 0) return \"back\";\n\n const confirm = await promptSelect(renderer, {\n title: \"pgsqlio · drop databases\",\n message: `Permanently drop ${selected.length} database(s)? This cannot be undone.`,\n allowBack: true,\n choices: [\n {\n name: \"Yes, drop selected databases\",\n description:\n selected.slice(0, 5).join(\", \") + (selected.length > 5 ? \"…\" : \"\"),\n value: \"yes\",\n },\n { name: \"Cancel\", description: \"Return to main menu\", value: \"no\" },\n ],\n });\n\n if (confirm === BACK || confirm === \"no\") return \"back\";\n\n const result = await withSpinner(\n renderer,\n \"pgsqlio · drop databases\",\n `Dropping ${selected.length} database(s)…`,\n () => dropDatabases(connUrl, selected),\n );\n\n await showStatus(renderer, {\n title: \"pgsqlio · drop databases\",\n message: result.ok\n ? `✅ Dropped ${selected.length} database(s)`\n : \"❌ Drop databases failed\",\n ok: result.ok,\n detail: result.ok ? selected.join(\", \") : result.output || undefined,\n });\n\n return result.ok ? \"ok\" : \"fail\";\n}\n"],"mappings":"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","names":["spawn","BoxRenderable","TextRenderable","SpinnerRenderable","BoxRenderable","TextRenderable","BoxRenderable","TextRenderable","quoteIdent","spawn","BoxRenderable","TextRenderable","SpinnerRenderable"]}
|
package/dist/cli.js
CHANGED
package/package.json
CHANGED
package/dist/app-YGK2LA7L.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/app.ts","../src/commands/dump.ts","../src/utils.ts","../src/tui/shared.ts","../src/tui/branding.ts","../src/commands/restore.ts","../src/commands/cleanup.ts","../src/commands/drop-databases.ts"],"sourcesContent":["import { createCliRenderer } from \"@opentui/core\";\nimport { runDumpFlow } from \"./commands/dump.js\";\nimport { runRestoreFlow } from \"./commands/restore.js\";\nimport { runCleanupFlow } from \"./commands/cleanup.js\";\nimport { runDropDatabasesFlow } from \"./commands/drop-databases.js\";\nimport { mountShell } from \"./tui/branding.js\";\nimport { BACK, promptSelect } from \"./tui/shared.js\";\n\nexport async function runApp(): Promise<void> {\n const renderer = await createCliRenderer({\n exitOnCtrlC: true,\n backgroundColor: \"#0C0C0C\",\n });\n\n renderer.start();\n mountShell(renderer);\n\n try {\n while (true) {\n const action = await promptSelect(renderer, {\n title: \"pgsqlio\",\n message: \"What do you want to do?\",\n choices: [\n {\n name: \"Dump\",\n description: \"Backup one or more databases\",\n value: \"dump\",\n },\n {\n name: \"Restore\",\n description: \"Import a .sql backup into a database\",\n value: \"restore\",\n },\n {\n name: \"Cleanup\",\n description: \"Drop and recreate the public schema\",\n value: \"cleanup\",\n },\n {\n name: \"Drop databases\",\n description: \"Select and permanently drop databases\",\n value: \"drop-databases\",\n },\n {\n name: \"Quit\",\n description: \"Exit pgsqlio\",\n value: \"quit\",\n },\n ],\n });\n\n if (action === BACK || action === \"quit\") break;\n\n if (action === \"dump\") await runDumpFlow(renderer);\n else if (action === \"restore\") await runRestoreFlow(renderer);\n else if (action === \"cleanup\") await runCleanupFlow(renderer);\n else if (action === \"drop-databases\")\n await runDropDatabasesFlow(renderer);\n }\n } finally {\n renderer.destroy();\n }\n}\n","import { createWriteStream, unlinkSync, type WriteStream } from \"node:fs\";\nimport { spawn } from \"node:child_process\";\nimport { finished, pipeline } from \"node:stream/promises\";\nimport {\n BoxRenderable,\n TextRenderable,\n type CliRenderer,\n type KeyEvent,\n} from \"@opentui/core\";\nimport { SpinnerRenderable } from \"opentui-spinner\";\nimport { replaceDbInUrl, requireBin, timestamp } from \"../utils.js\";\nimport {\n BACK,\n clearContent,\n promptDbUrlAndDatabases,\n promptMultiSelect,\n promptSelect,\n type FlowResult,\n} from \"../tui/shared.js\";\n\ntype OutputMode = \"separate\" | \"single\";\n\nconst PG_DUMP_ARGS = [\"--clean\", \"--if-exists\"] as const;\n\nfunction quoteIdent(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction sqlString(name: string): string {\n return `'${name.replace(/'/g, \"''\")}'`;\n}\n\nasync function waitExit(child: ReturnType<typeof spawn>): Promise<number | null> {\n if (child.exitCode !== null) return child.exitCode;\n return new Promise((resolve) => child.once(\"close\", resolve));\n}\n\nasync function dumpOne(url: string, outFile: string): Promise<boolean> {\n const child = spawn(\"pg_dump\", [...PG_DUMP_ARGS, url], {\n stdio: [\"ignore\", \"pipe\", \"inherit\"],\n });\n const out = createWriteStream(outFile);\n\n try {\n await pipeline(child.stdout!, out);\n } catch {\n return false;\n }\n\n return (await waitExit(child)) === 0;\n}\n\n/** Append one database dump into an open stream (does not end the stream). */\nasync function dumpAppend(\n url: string,\n out: WriteStream,\n dbName: string,\n): Promise<boolean> {\n // Create DB if missing, then connect — required for restore onto empty servers\n const header =\n `\\n--\\n-- Database: ${dbName}\\n--\\n` +\n `\\\\connect postgres\\n` +\n `SELECT format('CREATE DATABASE %I', ${sqlString(dbName)})\\n` +\n `WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = ${sqlString(dbName)})\\\\gexec\\n` +\n `\\\\connect ${quoteIdent(dbName)}\\n\\n`;\n\n await new Promise<void>((resolve, reject) => {\n out.write(header, (err) => (err ? reject(err) : resolve()));\n });\n\n const child = spawn(\"pg_dump\", [...PG_DUMP_ARGS, url], {\n stdio: [\"ignore\", \"pipe\", \"inherit\"],\n });\n child.stdout!.pipe(out, { end: false });\n\n try {\n await finished(child.stdout!);\n } catch {\n return false;\n }\n\n return (await waitExit(child)) === 0;\n}\n\nasync function runProgress(\n renderer: CliRenderer,\n dbUrl: string,\n selected: string[],\n outputMode: OutputMode,\n): Promise<number> {\n const content = clearContent(renderer);\n\n const ts = timestamp();\n let failed = 0;\n const combinedFile =\n outputMode === \"single\" ? `backup_combined_${ts}.sql` : null;\n\n const panel = new BoxRenderable(renderer, {\n id: \"progress-panel\",\n border: true,\n borderColor: \"#555555\",\n title:\n outputMode === \"single\"\n ? ` dumping ${selected.length} database(s) → one file `\n : ` dumping ${selected.length} database(s) `,\n flexDirection: \"column\",\n padding: 1,\n width: \"100%\",\n flexGrow: 1,\n });\n\n const status = new TextRenderable(renderer, {\n id: \"progress-status\",\n content: combinedFile ? `Writing ${combinedFile}…` : \"Starting…\",\n fg: \"#AAAAAA\",\n marginBottom: 1,\n });\n panel.add(status);\n\n type Row = {\n spinner: SpinnerRenderable;\n label: TextRenderable;\n };\n\n const rows = new Map<string, Row>();\n\n for (const db of selected) {\n const box = new BoxRenderable(renderer, {\n id: `row-${db}`,\n flexDirection: \"row\",\n alignItems: \"center\",\n height: 1,\n width: \"100%\",\n });\n const spinner = new SpinnerRenderable(renderer, {\n id: `spin-${db}`,\n name: \"dots\",\n color: \"#88CCFF\",\n autoplay: false,\n });\n const label = new TextRenderable(renderer, {\n id: `label-${db}`,\n content: ` ${db} pending`,\n fg: \"#888888\",\n marginLeft: 1,\n });\n box.add(spinner);\n box.add(label);\n panel.add(box);\n rows.set(db, { spinner, label });\n }\n\n content.add(panel);\n\n const combined = combinedFile ? createWriteStream(combinedFile) : null;\n if (combined) {\n combined.write(\n `-- pgsqlio combined dump\\n-- databases: ${selected.join(\", \")}\\n-- created: ${ts}\\n`,\n );\n }\n\n for (let i = 0; i < selected.length; i++) {\n const db = selected[i]!;\n const url = replaceDbInUrl(dbUrl, db);\n const row = rows.get(db)!;\n const outLabel = combinedFile ?? `backup_${db}_${ts}.sql`;\n\n status.content = `Dumping ${i + 1}/${selected.length}: ${db}`;\n row.label.content = ` ${db} → ${outLabel}`;\n row.label.fg = \"#FFFFFF\";\n row.spinner.start();\n\n const ok = combined\n ? await dumpAppend(url, combined, db)\n : await dumpOne(url, outLabel);\n\n row.spinner.stop();\n row.spinner.visible = false;\n\n if (ok) {\n row.label.content = `✓ ${db} → ${outLabel}`;\n row.label.fg = \"#66DD88\";\n } else {\n row.label.content = `✗ ${db} failed`;\n row.label.fg = \"#FF6666\";\n failed += 1;\n if (!combined) {\n try {\n unlinkSync(outLabel);\n } catch {\n /* ignore */\n }\n }\n }\n }\n\n if (combined) {\n await new Promise<void>((resolve, reject) => {\n combined.end(() => resolve());\n combined.on(\"error\", reject);\n });\n if (failed > 0) {\n try {\n unlinkSync(combinedFile!);\n } catch {\n /* ignore */\n }\n }\n }\n\n status.content =\n failed === 0\n ? combinedFile\n ? `Done — ${selected.length} database(s) → ${combinedFile}`\n : `Done — ${selected.length} database(s) dumped`\n : `Finished with ${failed} failure(s)`;\n status.fg = failed === 0 ? \"#66DD88\" : \"#FFAA66\";\n\n panel.add(\n new TextRenderable(renderer, {\n id: \"progress-done\",\n content: \"Press Enter to continue\",\n fg: \"#888888\",\n marginTop: 1,\n }),\n );\n\n await new Promise<void>((resolve) => {\n const onKey = (key: KeyEvent) => {\n if (key.name === \"return\" || key.name === \"enter\" || key.name === \"q\") {\n renderer.keyInput.off(\"keypress\", onKey);\n resolve();\n }\n };\n renderer.keyInput.on(\"keypress\", onKey);\n });\n\n return failed;\n}\n\nexport async function runDumpFlow(renderer: CliRenderer): Promise<FlowResult> {\n requireBin(\"psql\");\n requireBin(\"pg_dump\");\n\n let dbUrl: string;\n let databases: string[];\n try {\n const listed = await promptDbUrlAndDatabases(renderer, \"pgsqlio · dump\");\n dbUrl = listed.url;\n databases = listed.databases;\n } catch {\n return \"back\";\n }\n\n let selected: string[] | undefined;\n let outputMode: OutputMode = \"separate\";\n\n while (!selected) {\n const mode = await promptSelect(renderer, {\n title: \"pgsqlio · dump\",\n message: \"What do you want to dump?\",\n allowBack: true,\n choices: [\n {\n name: `All databases (${databases.length})`,\n description: \"Dump every non-template database\",\n value: \"all\",\n },\n {\n name: \"Select databases\",\n description: \"Pick databases with checkboxes\",\n value: \"select\",\n },\n ],\n });\n\n if (mode === BACK) return \"back\";\n\n if (mode === \"all\") {\n selected = [...databases];\n } else {\n const picks = await promptMultiSelect(renderer, {\n title: \"select databases\",\n items: databases,\n });\n if (picks === BACK) continue;\n if (picks.length === 0) continue;\n selected = picks;\n }\n\n if (selected.length > 1) {\n const fileMode = await promptSelect(renderer, {\n title: \"pgsqlio · dump\",\n message: `How should ${selected.length} databases be written?`,\n allowBack: true,\n choices: [\n {\n name: \"Separate files\",\n description: \"One backup_<db>_….sql file per database\",\n value: \"separate\" as const,\n },\n {\n name: \"Single file\",\n description: \"One backup_combined_….sql with \\\\connect between DBs\",\n value: \"single\" as const,\n },\n ],\n });\n\n if (fileMode === BACK) {\n selected = undefined;\n continue;\n }\n outputMode = fileMode;\n } else {\n outputMode = \"separate\";\n }\n }\n\n const failed = await runProgress(renderer, dbUrl, selected, outputMode);\n return failed === 0 ? \"ok\" : \"fail\";\n}\n","import { spawn, spawnSync } from \"node:child_process\";\n\nexport function requireBin(name: string): void {\n const result = spawnSync(name, [\"--version\"], { encoding: \"utf8\" });\n if (result.error || result.status !== 0) {\n console.error(`❌ Missing required binary: ${name} (install PostgreSQL client tools)`);\n process.exit(1);\n }\n}\n\nexport function run(\n cmd: string,\n args: string[],\n options?: { input?: string },\n): { ok: boolean; output: string } {\n const result = spawnSync(cmd, args, {\n encoding: \"utf8\",\n input: options?.input,\n stdio: options?.input !== undefined ? [\"pipe\", \"pipe\", \"pipe\"] : [\"ignore\", \"pipe\", \"pipe\"],\n });\n const output = [result.stdout, result.stderr].filter(Boolean).join(\"\\n\").trim();\n return { ok: result.status === 0, output };\n}\n\nexport function quoteIdent(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\n/** Create database if it does not exist (connect via adminUrl, usually …/postgres). */\nexport function ensureDatabase(adminUrl: string, name: string): { ok: boolean; output: string } {\n const lit = name.replace(/'/g, \"''\");\n const { ok: checkOk, stdout } = runCapture(\"psql\", [\n adminUrl,\n \"-Atc\",\n `SELECT 1 FROM pg_database WHERE datname = '${lit}'`,\n ]);\n if (checkOk && stdout.trim() === \"1\") {\n return { ok: true, output: \"\" };\n }\n return run(\"psql\", [adminUrl, \"-v\", \"ON_ERROR_STOP=1\", \"-c\", `CREATE DATABASE ${quoteIdent(name)}`]);\n}\n\n/** Reset public schema so a plain dump can restore without \"already exists\" errors. */\nexport function wipePublicSchema(dbUrl: string): { ok: boolean; output: string } {\n return run(\"psql\", [\n dbUrl,\n \"-v\",\n \"ON_ERROR_STOP=1\",\n \"-c\",\n \"DROP SCHEMA IF EXISTS public CASCADE; CREATE SCHEMA public; GRANT ALL ON SCHEMA public TO public; GRANT ALL ON SCHEMA public TO CURRENT_USER;\",\n ]);\n}\n\n/** Parse \\\\connect targets from a dump (for combined backups). */\nexport function extractConnectTargets(sql: string): string[] {\n const found = new Set<string>();\n for (const m of sql.matchAll(/\\\\connect\\s+\"((?:\\\\.|[^\"\\\\])*)\"/gi)) {\n found.add(m[1]!.replace(/\"\"/g, '\"'));\n }\n for (const m of sql.matchAll(/\\\\connect\\s+([^\\s\"]+)/gi)) {\n const name = m[1]!.replace(/;$/, \"\");\n if (name.toLowerCase() !== \"postgres\") found.add(name);\n }\n found.delete(\"postgres\");\n return [...found];\n}\n\nexport function runCapture(\n cmd: string,\n args: string[],\n): { ok: boolean; stdout: string; stderr: string } {\n const result = spawnSync(cmd, args, { encoding: \"utf8\" });\n return {\n ok: result.status === 0,\n stdout: (result.stdout ?? \"\").trim(),\n stderr: (result.stderr ?? \"\").trim(),\n };\n}\n\nexport function runCaptureAsync(\n cmd: string,\n args: string[],\n): Promise<{ ok: boolean; stdout: string; stderr: string }> {\n return new Promise((resolve) => {\n const child = spawn(cmd, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n const out: Buffer[] = [];\n const err: Buffer[] = [];\n child.stdout.on(\"data\", (chunk: Buffer) => out.push(chunk));\n child.stderr.on(\"data\", (chunk: Buffer) => err.push(chunk));\n child.on(\"error\", (error) => {\n resolve({ ok: false, stdout: \"\", stderr: error.message });\n });\n child.on(\"close\", (code) => {\n resolve({\n ok: code === 0,\n stdout: Buffer.concat(out).toString(\"utf8\").trim(),\n stderr: Buffer.concat(err).toString(\"utf8\").trim(),\n });\n });\n });\n}\n\n/** Ensure URL has a database path (defaults to postgres). */\nexport function normalizeConnUrl(url: string): string {\n const [base, query] = url.split(\"?\");\n let next = base ?? url;\n if (/^postgres(?:ql)?:\\/\\/[^/]+$/i.test(next)) {\n next = `${next}/postgres`;\n } else if (/^postgres(?:ql)?:\\/\\/[^/]+\\/$/i.test(next)) {\n next = `${next}postgres`;\n }\n return query !== undefined ? `${next}?${query}` : next;\n}\n\nexport function replaceDbInUrl(url: string, newDb: string): string {\n const normalized = normalizeConnUrl(url);\n const [base, query] = normalized.split(\"?\");\n const match = (base ?? normalized).match(/^(postgres(?:ql)?:\\/\\/[^/]+)/i);\n const authority = match?.[1] ?? (base ?? normalized).replace(/\\/[^/]*$/, \"\");\n const replaced = `${authority}/${newDb}`;\n return query !== undefined ? `${replaced}?${query}` : replaced;\n}\n\nexport function timestamp(): string {\n const d = new Date();\n const pad = (n: number) => String(n).padStart(2, \"0\");\n return (\n `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}_` +\n `${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`\n );\n}\n\nexport async function pingConnection(\n dbUrl: string,\n): Promise<{ ok: boolean; error?: string }> {\n const url = normalizeConnUrl(dbUrl);\n const { ok, stdout, stderr } = await runCaptureAsync(\"psql\", [\n url,\n \"-Atc\",\n \"SELECT 1\",\n ]);\n if (!ok) {\n return { ok: false, error: stderr || stdout || \"Connection failed\" };\n }\n return { ok: true };\n}\n\nexport async function listDatabases(\n dbUrl: string,\n): Promise<{ ok: boolean; databases: string[]; error?: string }> {\n const url = normalizeConnUrl(dbUrl);\n const { ok, stdout, stderr } = await runCaptureAsync(\"psql\", [\n url,\n \"-Atc\",\n \"SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname;\",\n ]);\n if (!ok) {\n return { ok: false, databases: [], error: stderr || stdout || \"Connection failed\" };\n }\n return { ok: true, databases: stdout.split(\"\\n\").filter(Boolean) };\n}\n\nexport function listTables(\n dbUrl: string,\n schema = \"public\",\n): { ok: boolean; tables: string[]; error?: string } {\n const url = normalizeConnUrl(dbUrl);\n const lit = schema.replace(/'/g, \"''\");\n const { ok, stdout, stderr } = runCapture(\"psql\", [\n url,\n \"-Atc\",\n `SELECT tablename FROM pg_tables WHERE schemaname = '${lit}' ORDER BY tablename;`,\n ]);\n if (!ok) {\n return { ok: false, tables: [], error: stderr || stdout || \"Connection failed\" };\n }\n return { ok: true, tables: stdout.split(\"\\n\").filter(Boolean) };\n}\n\nexport function dropTables(\n dbUrl: string,\n tables: string[],\n schema = \"public\",\n): { ok: boolean; output: string } {\n if (tables.length === 0) return { ok: true, output: \"\" };\n const qualified = tables\n .map((t) => `${quoteIdent(schema)}.${quoteIdent(t)}`)\n .join(\", \");\n return run(\"psql\", [\n dbUrl,\n \"-v\",\n \"ON_ERROR_STOP=1\",\n \"-c\",\n `DROP TABLE IF EXISTS ${qualified} CASCADE;`,\n ]);\n}\n\n/** Drop databases (connects via /postgres). Terminates backends when possible. */\nexport function dropDatabases(\n connUrl: string,\n names: string[],\n): { ok: boolean; output: string } {\n const adminUrl = replaceDbInUrl(normalizeConnUrl(connUrl), \"postgres\");\n const logs: string[] = [];\n\n for (const name of names) {\n if (name === \"postgres\" || name.startsWith(\"template\")) {\n return {\n ok: false,\n output: `Refusing to drop protected database: ${name}`,\n };\n }\n\n const lit = name.replace(/'/g, \"''\");\n // Kick connections so DROP DATABASE can proceed\n const terminate = run(\"psql\", [\n adminUrl,\n \"-c\",\n `SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '${lit}' AND pid <> pg_backend_pid();`,\n ]);\n if (terminate.output) logs.push(terminate.output);\n\n const dropped = run(\"psql\", [\n adminUrl,\n \"-v\",\n \"ON_ERROR_STOP=1\",\n \"-c\",\n `DROP DATABASE IF EXISTS ${quoteIdent(name)};`,\n ]);\n if (dropped.output) logs.push(dropped.output);\n if (!dropped.ok) {\n return {\n ok: false,\n output: [`Failed dropping \"${name}\"`, ...logs].filter(Boolean).join(\"\\n\"),\n };\n }\n }\n\n return { ok: true, output: logs.join(\"\\n\").trim() };\n}\n\nexport function printUsage(bin = \"pgsqlio\"): void {\n console.log(`Usage:\n ${bin}\n\nInteractive menu: Dump · Restore · Cleanup · Drop databases`);\n}\n","import {\n BoxRenderable,\n InputRenderable,\n InputRenderableEvents,\n SelectRenderable,\n SelectRenderableEvents,\n TextRenderable,\n type CliRenderer,\n type KeyEvent,\n type SelectOption,\n} from \"@opentui/core\";\nimport { SpinnerRenderable } from \"opentui-spinner\";\nimport { getContent } from \"./branding.js\";\nimport { listDatabases, normalizeConnUrl, pingConnection } from \"../utils.js\";\n\nexport type FlowResult = \"ok\" | \"fail\" | \"back\";\nexport const BACK = \"__back__\" as const;\n\n/** Clear only the content region — sticky branding stays. */\nexport function clearContent(renderer: CliRenderer): BoxRenderable {\n const content = getContent(renderer);\n for (const child of content.getChildren()) {\n content.remove(child.id);\n }\n return content;\n}\n\n/** @deprecated use clearContent — kept as alias for call sites */\nexport const clearRoot = clearContent;\n\nexport function looksLikePgUrl(value: string): boolean {\n return /^(postgres(ql)?:\\/\\/)/i.test(value.trim());\n}\n\n/** Checkbox multi-select with ← Back. Returns BACK or selected item ids. */\nexport function promptMultiSelect(\n renderer: CliRenderer,\n options: {\n title: string;\n items: string[];\n emptyMessage?: string;\n },\n): Promise<string[] | typeof BACK> {\n return new Promise((resolve) => {\n const { items } = options;\n if (items.length === 0) {\n resolve([]);\n return;\n }\n\n const content = clearContent(renderer);\n const choices = [BACK, ...items];\n const checked = new Set<string>();\n let cursor = 1;\n\n const panel = new BoxRenderable(renderer, {\n id: \"pick-panel\",\n border: true,\n borderColor: \"#555555\",\n title: ` ${options.title} `,\n flexDirection: \"column\",\n padding: 1,\n width: \"100%\",\n flexGrow: 1,\n });\n\n panel.add(\n new TextRenderable(renderer, {\n id: \"pick-hint\",\n content: \"Space toggle · a all · Enter confirm · Esc back\",\n fg: \"#888888\",\n marginBottom: 1,\n }),\n );\n\n const list = new BoxRenderable(renderer, {\n id: \"pick-list\",\n flexDirection: \"column\",\n flexGrow: 1,\n width: \"100%\",\n });\n\n const lines: TextRenderable[] = choices.map((_, i) => {\n const line = new TextRenderable(renderer, {\n id: `pick-line-${i}`,\n content: \"\",\n fg: \"#CCCCCC\",\n });\n list.add(line);\n return line;\n });\n\n panel.add(list);\n content.add(panel);\n\n const redraw = () => {\n for (let i = 0; i < choices.length; i++) {\n const id = choices[i]!;\n const isBack = id === BACK;\n const marker = isBack ? \" \" : checked.has(id) ? \"[x]\" : \"[ ]\";\n const pointer = i === cursor ? \"▶\" : \" \";\n const label = isBack ? \"← Back\" : id;\n lines[i]!.content = `${pointer} ${marker} ${label}`;\n lines[i]!.fg = i === cursor ? \"#FFFF66\" : isBack ? \"#88AADD\" : \"#CCCCCC\";\n }\n };\n\n redraw();\n\n const onKey = (key: KeyEvent) => {\n if (key.name === \"up\" || key.name === \"k\") {\n cursor = Math.max(0, cursor - 1);\n redraw();\n return;\n }\n if (key.name === \"down\" || key.name === \"j\") {\n cursor = Math.min(choices.length - 1, cursor + 1);\n redraw();\n return;\n }\n if (key.name === \"space\") {\n const id = choices[cursor]!;\n if (id === BACK) {\n cleanup();\n resolve(BACK);\n return;\n }\n if (checked.has(id)) checked.delete(id);\n else checked.add(id);\n redraw();\n return;\n }\n if (key.name === \"a\") {\n if (checked.size === items.length) checked.clear();\n else items.forEach((item) => checked.add(item));\n redraw();\n return;\n }\n if (key.name === \"escape\") {\n cleanup();\n resolve(BACK);\n return;\n }\n if (key.name === \"return\" || key.name === \"enter\") {\n const id = choices[cursor]!;\n if (id === BACK) {\n cleanup();\n resolve(BACK);\n return;\n }\n if (checked.size === 0) return;\n cleanup();\n resolve([...checked]);\n }\n };\n\n const cleanup = () => {\n renderer.keyInput.off(\"keypress\", onKey);\n };\n\n renderer.keyInput.on(\"keypress\", onKey);\n });\n}\n\nexport function promptSelect<T extends string>(\n renderer: CliRenderer,\n options: {\n title: string;\n message: string;\n hint?: string;\n choices: Array<{ name: string; description: string; value: T }>;\n allowBack?: boolean;\n },\n): Promise<T | typeof BACK> {\n return new Promise((resolve, reject) => {\n const content = clearContent(renderer);\n\n const panel = new BoxRenderable(renderer, {\n id: \"select-panel\",\n border: true,\n borderColor: \"#555555\",\n title: ` ${options.title} `,\n flexDirection: \"column\",\n padding: 1,\n width: \"100%\",\n flexGrow: 1,\n });\n\n panel.add(\n new TextRenderable(renderer, {\n id: \"select-message\",\n content: options.message,\n fg: \"#FFFFFF\",\n marginBottom: 1,\n }),\n );\n\n const menu = new SelectRenderable(renderer, {\n id: \"select-menu\",\n width: \"100%\",\n height: Math.max(4, options.choices.length * 2 + 1),\n showDescription: true,\n showScrollIndicator: false,\n options: options.choices.map(\n (c): SelectOption => ({\n name: c.name,\n description: c.description,\n value: c.value,\n }),\n ),\n });\n\n panel.add(menu);\n panel.add(\n new TextRenderable(renderer, {\n id: \"select-hint\",\n content:\n options.hint ??\n (options.allowBack\n ? \"↑/↓ move · Enter confirm · Esc back\"\n : \"↑/↓ move · Enter confirm · Ctrl+C quit\"),\n fg: \"#888888\",\n marginTop: 1,\n }),\n );\n\n content.add(panel);\n menu.focus();\n\n const onSelect = (_index: number, option: SelectOption) => {\n cleanup();\n resolve(option.value as T);\n };\n\n const onKey = (key: KeyEvent) => {\n if (key.name === \"escape\") {\n cleanup();\n if (options.allowBack) resolve(BACK);\n else reject(new Error(\"cancelled\"));\n }\n };\n\n const cleanup = () => {\n menu.off(SelectRenderableEvents.ITEM_SELECTED, onSelect);\n renderer.keyInput.off(\"keypress\", onKey);\n };\n\n menu.on(SelectRenderableEvents.ITEM_SELECTED, onSelect);\n renderer.keyInput.on(\"keypress\", onKey);\n });\n}\n\nfunction yieldFrame(): Promise<void> {\n return new Promise((resolve) => setImmediate(resolve));\n}\n\nexport function promptText(\n renderer: CliRenderer,\n options: {\n title: string;\n label: string;\n placeholder?: string;\n initial?: string;\n hint?: string;\n maxLength?: number;\n busyMessage?: string;\n validate?: (value: string) => string | null;\n verify?: (value: string) => Promise<string | null>;\n },\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const content = clearContent(renderer);\n\n const panel = new BoxRenderable(renderer, {\n id: \"text-panel\",\n border: true,\n borderColor: \"#555555\",\n title: ` ${options.title} `,\n flexDirection: \"column\",\n padding: 1,\n width: \"100%\",\n flexGrow: 1,\n gap: 1,\n });\n\n panel.add(\n new TextRenderable(renderer, {\n id: \"text-label\",\n content: options.label,\n fg: \"#FFFFFF\",\n }),\n );\n\n const inputFrame = new BoxRenderable(renderer, {\n id: \"text-input-frame\",\n width: \"100%\",\n padding: 1,\n backgroundColor: \"#2A2A2A\",\n });\n\n const input = new InputRenderable(renderer, {\n id: \"text-input\",\n width: \"100%\",\n placeholder: options.placeholder ?? \"\",\n value: options.initial?.trim() ?? \"\",\n maxLength: options.maxLength ?? 2000,\n backgroundColor: \"#2A2A2A\",\n focusedBackgroundColor: \"#2A2A2A\",\n textColor: \"#FFFFFF\",\n cursorColor: \"#88CCFF\",\n });\n\n inputFrame.add(input);\n\n const statusRow = new BoxRenderable(renderer, {\n id: \"text-status-row\",\n flexDirection: \"row\",\n alignItems: \"center\",\n width: \"100%\",\n height: 1,\n });\n const spin = new SpinnerRenderable(renderer, {\n name: \"dots\",\n color: \"#88CCFF\",\n autoplay: false,\n });\n spin.visible = false;\n const statusText = new TextRenderable(renderer, {\n id: \"text-status\",\n content: \"\",\n fg: \"#FF6666\",\n marginLeft: 1,\n });\n statusRow.add(spin);\n statusRow.add(statusText);\n\n panel.add(inputFrame);\n panel.add(statusRow);\n panel.add(\n new TextRenderable(renderer, {\n id: \"text-hint\",\n content: options.hint ?? \"Enter confirm · Esc back\",\n fg: \"#888888\",\n }),\n );\n\n content.add(panel);\n input.focus();\n\n let busy = false;\n let cancelled = false;\n\n const setBusy = (on: boolean, message = \"\") => {\n busy = on;\n if (on) {\n spin.visible = true;\n spin.start();\n statusText.content = message;\n statusText.fg = \"#CCCCCC\";\n } else {\n spin.stop();\n spin.visible = false;\n statusText.content = \"\";\n }\n };\n\n const setError = (msg: string) => {\n spin.stop();\n spin.visible = false;\n busy = false;\n statusText.content = msg;\n statusText.fg = \"#FF6666\";\n input.focus();\n };\n\n const submit = async (value: string) => {\n if (busy) return;\n const trimmed = value.trim();\n if (!trimmed) {\n setError(\"Value is required\");\n return;\n }\n if (options.validate) {\n const msg = options.validate(trimmed);\n if (msg) {\n setError(msg);\n return;\n }\n }\n if (options.verify) {\n setBusy(true, options.busyMessage ?? \"Working…\");\n input.blur();\n await yieldFrame();\n try {\n const msg = await options.verify(trimmed);\n if (cancelled) return;\n if (msg) {\n setError(msg);\n return;\n }\n } catch (err) {\n if (cancelled) return;\n setError(err instanceof Error ? err.message : \"Failed\");\n return;\n }\n if (cancelled) return;\n setBusy(false);\n }\n cleanup();\n resolve(trimmed);\n };\n\n const onEnter = (value: string) => {\n void submit(value);\n };\n const onKey = (key: KeyEvent) => {\n if (key.name === \"escape\") {\n cleanup();\n reject(new Error(\"cancelled\"));\n }\n };\n\n const cleanup = () => {\n cancelled = true;\n busy = false;\n spin.stop();\n input.off(InputRenderableEvents.ENTER, onEnter);\n renderer.keyInput.off(\"keypress\", onKey);\n };\n\n input.on(InputRenderableEvents.ENTER, onEnter);\n renderer.keyInput.on(\"keypress\", onKey);\n });\n}\n\nexport function promptDbUrl(\n renderer: CliRenderer,\n title: string,\n options?: {\n initial?: string;\n busyMessage?: string;\n verify?: (url: string) => Promise<string | null>;\n },\n): Promise<string> {\n const verify =\n options?.verify ??\n (async (url: string) => {\n const ping = await pingConnection(url);\n return ping.ok ? null : ping.error ?? \"Connection failed\";\n });\n\n return promptText(renderer, {\n title,\n label: \"PostgreSQL connection URL\",\n placeholder: \"postgresql://user:password@host:5432\",\n initial: options?.initial,\n hint: \"Enter confirm · Esc back · database name optional (you can pick next)\",\n busyMessage: options?.busyMessage ?? \"Connecting…\",\n validate: (value) =>\n looksLikePgUrl(value)\n ? null\n : \"URL must start with postgresql:// or postgres://\",\n verify: (value) => verify(normalizeConnUrl(value)),\n }).then(normalizeConnUrl);\n}\n\n/** Prompt for a URL and fetch the database list on the same screen. */\nexport async function promptDbUrlAndDatabases(\n renderer: CliRenderer,\n title: string,\n options?: {\n initial?: string;\n emptyMessage?: string;\n filter?: (name: string) => boolean;\n },\n): Promise<{ url: string; databases: string[] }> {\n let databases: string[] = [];\n const url = await promptDbUrl(renderer, title, {\n initial: options?.initial,\n busyMessage: \"Fetching databases…\",\n verify: async (value) => {\n const listed = await listDatabases(value);\n if (!listed.ok) return listed.error ?? \"Connection failed\";\n const next = options?.filter\n ? listed.databases.filter(options.filter)\n : listed.databases;\n if (next.length === 0) {\n return options?.emptyMessage ?? \"No databases found\";\n }\n databases = next;\n return null;\n },\n });\n return { url, databases };\n}\n\nexport async function waitForEnter(\n renderer: CliRenderer,\n message = \"Press Enter to continue\",\n): Promise<void> {\n const content = getContent(renderer);\n const hint = new TextRenderable(renderer, {\n id: `wait-enter-${Date.now()}`,\n content: message,\n fg: \"#888888\",\n marginTop: 1,\n });\n\n const children = content.getChildren();\n const last = children[children.length - 1];\n if (last) {\n try {\n (last as BoxRenderable).add(hint);\n } catch {\n content.add(hint);\n }\n } else {\n content.add(hint);\n }\n\n await new Promise<void>((resolve) => {\n const onKey = (key: KeyEvent) => {\n if (key.name === \"return\" || key.name === \"enter\" || key.name === \"q\") {\n renderer.keyInput.off(\"keypress\", onKey);\n resolve();\n }\n };\n renderer.keyInput.on(\"keypress\", onKey);\n });\n}\n\nexport async function showStatus(\n renderer: CliRenderer,\n options: {\n title: string;\n message: string;\n ok: boolean;\n detail?: string;\n },\n): Promise<void> {\n const content = clearContent(renderer);\n const panel = new BoxRenderable(renderer, {\n id: \"status-panel\",\n border: true,\n borderColor: \"#555555\",\n title: ` ${options.title} `,\n flexDirection: \"column\",\n padding: 1,\n width: \"100%\",\n flexGrow: 1,\n });\n panel.add(\n new TextRenderable(renderer, {\n content: options.message,\n fg: options.ok ? \"#66DD88\" : \"#FF6666\",\n marginBottom: options.detail ? 1 : 0,\n }),\n );\n if (options.detail) {\n const lines = options.detail.split(\"\\n\").filter(Boolean).slice(-8);\n for (const [i, line] of lines.entries()) {\n panel.add(\n new TextRenderable(renderer, {\n id: `status-detail-${i}`,\n content: line.length > 100 ? `${line.slice(0, 97)}…` : line,\n fg: \"#A1A1AA\",\n }),\n );\n }\n }\n content.add(panel);\n await waitForEnter(renderer);\n}\n\nexport async function withSpinner<T>(\n renderer: CliRenderer,\n title: string,\n label: string,\n work: () => Promise<T> | T,\n): Promise<T> {\n const content = clearContent(renderer);\n const panel = new BoxRenderable(renderer, {\n id: \"spinner-panel\",\n border: true,\n borderColor: \"#555555\",\n title: ` ${title} `,\n flexDirection: \"row\",\n alignItems: \"center\",\n padding: 1,\n width: \"100%\",\n flexGrow: 1,\n });\n const spin = new SpinnerRenderable(renderer, {\n id: \"work-spin\",\n name: \"dots\",\n color: \"#88CCFF\",\n });\n panel.add(spin);\n panel.add(\n new TextRenderable(renderer, {\n content: ` ${label}`,\n fg: \"#CCCCCC\",\n marginLeft: 1,\n }),\n );\n content.add(panel);\n await yieldFrame();\n try {\n return await work();\n } finally {\n spin.stop();\n }\n}\n","import {\n ASCIIFontRenderable,\n BoxRenderable,\n TextRenderable,\n type CliRenderer,\n} from \"@opentui/core\";\n\nexport const SHELL_ID = \"app-shell\";\nexport const CONTENT_ID = \"app-content\";\nconst VERSION = \"0.1.0\";\n\nfunction createHeader(renderer: CliRenderer): BoxRenderable {\n const header = new BoxRenderable(renderer, {\n id: \"app-header\",\n width: \"100%\",\n flexDirection: \"column\",\n flexShrink: 0,\n });\n\n const logo = new BoxRenderable(renderer, {\n id: \"branding-logo\",\n position: \"relative\",\n marginBottom: 0,\n });\n\n logo.add(\n new ASCIIFontRenderable(renderer, {\n id: \"branding-shadow\",\n text: \"pgsqlio\",\n font: \"block\",\n color: \"#1A2228\",\n position: \"absolute\",\n left: 1,\n top: 1,\n zIndex: 0,\n }),\n );\n\n logo.add(\n new ASCIIFontRenderable(renderer, {\n id: \"branding-wordmark\",\n text: \"pgsqlio\",\n font: \"block\",\n color: [\"#2DD4BF\", \"#67E8F9\", \"#E0F2FE\"],\n zIndex: 1,\n }),\n );\n\n header.add(logo);\n header.add(\n new TextRenderable(renderer, {\n id: \"branding-tagline\",\n content: `PostgreSQL dump · restore · cleanup · v${VERSION}`,\n fg: \"#3F3F46\",\n marginTop: 1,\n }),\n );\n\n return header;\n}\n\n/** Mount sticky branding + content region. Call once at app start. */\nexport function mountShell(renderer: CliRenderer): BoxRenderable {\n for (const child of renderer.root.getChildren()) {\n renderer.root.remove(child.id);\n }\n\n const shell = new BoxRenderable(renderer, {\n id: SHELL_ID,\n width: \"100%\",\n height: \"100%\",\n flexDirection: \"column\",\n backgroundColor: \"#0C0C0C\",\n padding: 1,\n });\n\n shell.add(createHeader(renderer));\n\n const content = new BoxRenderable(renderer, {\n id: CONTENT_ID,\n width: \"100%\",\n flexGrow: 1,\n flexShrink: 1,\n flexDirection: \"column\",\n marginTop: 1,\n });\n shell.add(content);\n renderer.root.add(shell);\n return content;\n}\n\nexport function getContent(renderer: CliRenderer): BoxRenderable {\n const shell = renderer.root.getChildren().find((c) => c.id === SHELL_ID) as\n | BoxRenderable\n | undefined;\n if (!shell) {\n return mountShell(renderer);\n }\n const content = shell.getChildren().find((c) => c.id === CONTENT_ID) as\n | BoxRenderable\n | undefined;\n if (!content) {\n return mountShell(renderer);\n }\n return content;\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport type { CliRenderer } from \"@opentui/core\";\nimport {\n ensureDatabase,\n extractConnectTargets,\n replaceDbInUrl,\n requireBin,\n run,\n wipePublicSchema,\n} from \"../utils.js\";\nimport {\n promptDbUrl,\n promptSelect,\n promptText,\n showStatus,\n withSpinner,\n BACK,\n type FlowResult,\n} from \"../tui/shared.js\";\n\nexport async function runRestoreFlow(renderer: CliRenderer): Promise<FlowResult> {\n requireBin(\"psql\");\n\n let dbUrl: string;\n try {\n dbUrl = await promptDbUrl(renderer, \"pgsqlio · restore\");\n } catch {\n return \"back\";\n }\n\n let file: string;\n try {\n file = await promptText(renderer, {\n title: \"pgsqlio · restore\",\n label: \"SQL backup file path\",\n placeholder: \"backup_mydb_20250924_121530.sql\",\n validate: (value) =>\n existsSync(value) ? null : \"File not found — check the path\",\n });\n } catch {\n return \"back\";\n }\n\n let sql = \"\";\n try {\n sql = readFileSync(file, \"utf8\");\n } catch {\n await showStatus(renderer, {\n title: \"pgsqlio · restore\",\n message: \"❌ Could not read backup file\",\n ok: false,\n });\n return \"fail\";\n }\n\n const targets = extractConnectTargets(sql);\n const isCombined = targets.length > 0;\n const adminUrl = replaceDbInUrl(dbUrl, \"postgres\");\n\n const confirm = await promptSelect(renderer, {\n title: \"pgsqlio · restore\",\n message: isCombined\n ? `Restore ${targets.length} database(s) from ${file}?`\n : `Restore into this database from ${file}?`,\n allowBack: true,\n choices: [\n {\n name: \"Wipe schemas, then restore\",\n description:\n \"DROP SCHEMA public CASCADE on target DB(s) first (fixes “already exists”)\",\n value: \"wipe\",\n },\n {\n name: \"Restore as-is\",\n description: \"Do not wipe — fails if objects already exist\",\n value: \"asis\",\n },\n { name: \"Cancel\", description: \"Return to main menu\", value: \"no\" },\n ],\n });\n\n if (confirm === BACK || confirm === \"no\") return \"back\";\n const wipeFirst = confirm === \"wipe\";\n\n const result = await withSpinner(\n renderer,\n \"pgsqlio · restore\",\n wipeFirst ? \"Wiping + restoring…\" : \"Restoring…\",\n () => {\n const logs: string[] = [];\n\n if (isCombined) {\n for (const db of targets) {\n const created = ensureDatabase(adminUrl, db);\n if (!created.ok) {\n return {\n ok: false,\n output: [`Failed creating database \"${db}\"`, created.output]\n .filter(Boolean)\n .join(\"\\n\"),\n };\n }\n if (created.output) logs.push(created.output);\n\n if (wipeFirst) {\n const wiped = wipePublicSchema(replaceDbInUrl(adminUrl, db));\n if (!wiped.ok) {\n return {\n ok: false,\n output: [`Failed wiping database \"${db}\"`, wiped.output]\n .filter(Boolean)\n .join(\"\\n\"),\n };\n }\n if (wiped.output) logs.push(wiped.output);\n }\n }\n } else if (wipeFirst) {\n const wiped = wipePublicSchema(dbUrl);\n if (!wiped.ok) {\n return {\n ok: false,\n output: [\"Failed wiping target database\", wiped.output]\n .filter(Boolean)\n .join(\"\\n\"),\n };\n }\n if (wiped.output) logs.push(wiped.output);\n }\n\n // Combined dumps switch DB via \\\\connect — start on postgres so meta-commands work\n const restoreUrl = isCombined ? adminUrl : dbUrl;\n const restored = run(\"psql\", [\n restoreUrl,\n \"-v\",\n \"ON_ERROR_STOP=1\",\n \"-f\",\n file,\n ]);\n if (restored.output) logs.push(restored.output);\n return {\n ok: restored.ok,\n output: logs.join(\"\\n\").trim(),\n };\n },\n );\n\n await showStatus(renderer, {\n title: \"pgsqlio · restore\",\n message: result.ok ? \"✅ Restore successful\" : \"❌ Restore failed\",\n ok: result.ok,\n detail: result.ok ? undefined : result.output || undefined,\n });\n\n return result.ok ? \"ok\" : \"fail\";\n}\n","import type { CliRenderer } from \"@opentui/core\";\nimport { requireBin, run } from \"../utils.js\";\nimport {\n BACK,\n promptDbUrl,\n promptSelect,\n showStatus,\n withSpinner,\n type FlowResult,\n} from \"../tui/shared.js\";\n\nexport async function runCleanupFlow(renderer: CliRenderer): Promise<FlowResult> {\n requireBin(\"psql\");\n\n let dbUrl: string;\n try {\n dbUrl = await promptDbUrl(renderer, \"pgsqlio · cleanup\");\n } catch {\n return \"back\";\n }\n\n const confirm = await promptSelect(renderer, {\n title: \"pgsqlio · cleanup\",\n message: \"Drop and recreate the public schema? This is destructive.\",\n allowBack: true,\n choices: [\n {\n name: \"Yes, clean database\",\n description: \"DROP SCHEMA public CASCADE; CREATE SCHEMA public;\",\n value: \"yes\",\n },\n { name: \"Cancel\", description: \"Return to main menu\", value: \"no\" },\n ],\n });\n\n if (confirm === BACK || confirm === \"no\") return \"back\";\n\n const result = await withSpinner(renderer, \"pgsqlio · cleanup\", \"Cleaning…\", () =>\n run(\"psql\", [\n dbUrl,\n \"-v\",\n \"ON_ERROR_STOP=1\",\n \"-c\",\n \"DROP SCHEMA public CASCADE; CREATE SCHEMA public;\",\n ]),\n );\n\n await showStatus(renderer, {\n title: \"pgsqlio · cleanup\",\n message: result.ok\n ? \"✅ Cleanup successful (database is empty)\"\n : \"❌ Cleanup failed\",\n ok: result.ok,\n detail: result.ok ? undefined : result.output || undefined,\n });\n\n return result.ok ? \"ok\" : \"fail\";\n}\n","import type { CliRenderer } from \"@opentui/core\";\nimport { dropDatabases, requireBin } from \"../utils.js\";\nimport {\n BACK,\n promptDbUrlAndDatabases,\n promptMultiSelect,\n promptSelect,\n showStatus,\n withSpinner,\n type FlowResult,\n} from \"../tui/shared.js\";\n\nexport async function runDropDatabasesFlow(\n renderer: CliRenderer,\n): Promise<FlowResult> {\n requireBin(\"psql\");\n\n let connUrl: string;\n let droppable: string[];\n try {\n const listed = await promptDbUrlAndDatabases(\n renderer,\n \"pgsqlio · drop databases\",\n {\n filter: (name) => name !== \"postgres\" && !name.startsWith(\"template\"),\n emptyMessage:\n \"No droppable databases found (postgres / template* are protected)\",\n },\n );\n connUrl = listed.url;\n droppable = listed.databases;\n } catch {\n return \"back\";\n }\n\n const selected = await promptMultiSelect(renderer, {\n title: \"select databases to drop\",\n items: droppable,\n });\n\n if (selected === BACK) return \"back\";\n if (selected.length === 0) return \"back\";\n\n const confirm = await promptSelect(renderer, {\n title: \"pgsqlio · drop databases\",\n message: `Permanently drop ${selected.length} database(s)? This cannot be undone.`,\n allowBack: true,\n choices: [\n {\n name: \"Yes, drop selected databases\",\n description:\n selected.slice(0, 5).join(\", \") + (selected.length > 5 ? \"…\" : \"\"),\n value: \"yes\",\n },\n { name: \"Cancel\", description: \"Return to main menu\", value: \"no\" },\n ],\n });\n\n if (confirm === BACK || confirm === \"no\") return \"back\";\n\n const result = await withSpinner(\n renderer,\n \"pgsqlio · drop databases\",\n `Dropping ${selected.length} database(s)…`,\n () => dropDatabases(connUrl, selected),\n );\n\n await showStatus(renderer, {\n title: \"pgsqlio · drop databases\",\n message: result.ok\n ? `✅ Dropped ${selected.length} database(s)`\n : \"❌ Drop databases failed\",\n ok: result.ok,\n detail: result.ok ? selected.join(\", \") : result.output || undefined,\n });\n\n return result.ok ? \"ok\" : \"fail\";\n}\n"],"mappings":"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","names":["spawn","BoxRenderable","TextRenderable","SpinnerRenderable","BoxRenderable","TextRenderable","BoxRenderable","TextRenderable","quoteIdent","spawn","BoxRenderable","TextRenderable","SpinnerRenderable"]}
|