@happyvertical/sql 0.80.0 → 0.80.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.
Files changed (31) hide show
  1. package/dist/backup/index.js +210 -188
  2. package/dist/backup/index.js.map +1 -1
  3. package/dist/chunks/alter-utils-K7tiuj5L.js +135 -0
  4. package/dist/chunks/alter-utils-K7tiuj5L.js.map +1 -0
  5. package/dist/chunks/duckdb-DykBBzd6.js +1056 -0
  6. package/dist/chunks/duckdb-DykBBzd6.js.map +1 -0
  7. package/dist/chunks/duckdb-schema-utils-B-XBP8QF.js +115 -0
  8. package/dist/chunks/duckdb-schema-utils-B-XBP8QF.js.map +1 -0
  9. package/dist/chunks/postgres-cli-DzZcXSIG.js +272 -0
  10. package/dist/chunks/postgres-cli-DzZcXSIG.js.map +1 -0
  11. package/dist/chunks/schema-manager-a8RlxIE2.js +450 -0
  12. package/dist/chunks/schema-manager-a8RlxIE2.js.map +1 -0
  13. package/dist/chunks/sqlite-YgU9LCVy.js +1045 -0
  14. package/dist/chunks/sqlite-YgU9LCVy.js.map +1 -0
  15. package/dist/chunks/sqlite-native-BGtpx7Ro.js +902 -0
  16. package/dist/chunks/sqlite-native-BGtpx7Ro.js.map +1 -0
  17. package/dist/cli/claude-context.js +17 -17
  18. package/dist/cli/claude-context.js.map +1 -1
  19. package/dist/index.js +3244 -35
  20. package/dist/index.js.map +1 -1
  21. package/package.json +5 -5
  22. package/dist/chunks/duckdb-B6m78QdL.js +0 -924
  23. package/dist/chunks/duckdb-B6m78QdL.js.map +0 -1
  24. package/dist/chunks/index-CzdYvRFp.js +0 -3692
  25. package/dist/chunks/index-CzdYvRFp.js.map +0 -1
  26. package/dist/chunks/postgres-cli-Cr6bBZ3q.js +0 -209
  27. package/dist/chunks/postgres-cli-Cr6bBZ3q.js.map +0 -1
  28. package/dist/chunks/sqlite-CPCNeJIH.js +0 -937
  29. package/dist/chunks/sqlite-CPCNeJIH.js.map +0 -1
  30. package/dist/chunks/sqlite-native-DqVPKNUu.js +0 -1129
  31. package/dist/chunks/sqlite-native-DqVPKNUu.js.map +0 -1
@@ -1,209 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { mkdir, chmod } from "node:fs/promises";
3
- import { dirname } from "node:path";
4
- function databaseNameFromUrl(databaseUrl) {
5
- const url = new URL(databaseUrl);
6
- const database = decodeURIComponent(url.pathname.replace(/^\/+/u, ""));
7
- if (!database) throw new Error("Database URL must include a database name.");
8
- return database;
9
- }
10
- function isLocalDatabaseUrl(databaseUrl) {
11
- try {
12
- const url = new URL(databaseUrl);
13
- const hostname = url.hostname.toLowerCase().replace(/^\[|\]$/gu, "");
14
- return hostname === "" || hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
15
- } catch {
16
- return false;
17
- }
18
- }
19
- function redactDatabaseUrl(databaseUrl) {
20
- try {
21
- const url = new URL(databaseUrl);
22
- if (url.username) url.username = "***";
23
- if (url.password) url.password = "***";
24
- for (const param of ["password", "passwd", "pass"]) {
25
- if (url.searchParams.has(param)) {
26
- url.searchParams.set(param, "***");
27
- }
28
- }
29
- return url.toString();
30
- } catch {
31
- return "[invalid database url]";
32
- }
33
- }
34
- function postgresEnvFromUrl(databaseUrl, databaseOverride) {
35
- const url = new URL(databaseUrl);
36
- if (url.protocol !== "postgres:" && url.protocol !== "postgresql:") {
37
- throw new Error(`Unsupported database URL protocol: ${url.protocol}`);
38
- }
39
- const env = {};
40
- const database = databaseOverride ?? databaseNameFromUrl(databaseUrl);
41
- env.PGDATABASE = database;
42
- if (url.hostname) {
43
- env.PGHOST = url.hostname.replace(/^\[|\]$/gu, "");
44
- }
45
- if (url.port) env.PGPORT = url.port;
46
- if (url.username) env.PGUSER = decodeUserInfo(url.username);
47
- const passwordFromUrl = url.password && decodeUserInfo(url.password) || url.searchParams.get("password") || url.searchParams.get("passwd") || url.searchParams.get("pass") || "";
48
- if (passwordFromUrl) env.PGPASSWORD = passwordFromUrl;
49
- for (const [param, envName] of [
50
- ["sslmode", "PGSSLMODE"],
51
- ["sslrootcert", "PGSSLROOTCERT"],
52
- ["sslcert", "PGSSLCERT"],
53
- ["sslkey", "PGSSLKEY"]
54
- ]) {
55
- const value = url.searchParams.get(param);
56
- if (value) env[envName] = value;
57
- }
58
- return env;
59
- }
60
- const LIBPQ_INHERITANCE_VARS = [
61
- "PGHOST",
62
- "PGHOSTADDR",
63
- "PGPORT",
64
- "PGSERVICE",
65
- "PGSERVICEFILE"
66
- ];
67
- function assertCanExportDatabase(databaseUrl, options) {
68
- const local = isLocalDatabaseUrl(databaseUrl);
69
- if (options.prod && local && !options.allowLocal) {
70
- throw new Error(
71
- "Refusing to run a production-flavored export against a local database. Pass allowLocal only when intentionally testing the production export path."
72
- );
73
- }
74
- if (!options.prod && !local && !options.allowProduction) {
75
- throw new Error(
76
- "Refusing to export a non-local database without allowProduction. Use the production export path, or pass allowProduction intentionally."
77
- );
78
- }
79
- }
80
- function assertCanImportDatabase(databaseUrl, options) {
81
- if (!isLocalDatabaseUrl(databaseUrl) && !options.allowProduction) {
82
- throw new Error(
83
- "Refusing to import into a non-local database without allowProduction."
84
- );
85
- }
86
- }
87
- async function dumpPostgresDatabase(databaseUrl, dumpPath, options = {}) {
88
- await mkdir(dirname(dumpPath), { recursive: true, mode: 448 });
89
- await runCommand(
90
- options.binary ?? "pg_dump",
91
- [
92
- "--format=custom",
93
- "--no-owner",
94
- "--no-acl",
95
- "--file",
96
- dumpPath,
97
- ...options.extraArgs ?? []
98
- ],
99
- { env: postgresEnvFromUrl(databaseUrl) }
100
- );
101
- await chmod(dumpPath, 384);
102
- }
103
- async function restorePostgresDatabase(databaseUrl, dumpPath, options = {}) {
104
- const singleTransaction = options.singleTransaction ?? true;
105
- await runCommand(
106
- options.binary ?? "pg_restore",
107
- [
108
- "--clean",
109
- "--if-exists",
110
- "--no-owner",
111
- "--no-acl",
112
- // Atomic-restore default: wrap the whole operation in one
113
- // transaction. Without this, a mid-restore failure (e.g. a unique
114
- // constraint conflict halfway through data load) leaves the
115
- // target database with the `--clean` DROPs applied AND part of
116
- // the new schema/data, while pg_restore still exits non-zero —
117
- // operationally the worst of both worlds. Caller can opt out via
118
- // `singleTransaction: false` when running parallel restores
119
- // (`--jobs N`) since pg_restore rejects the combination.
120
- ...singleTransaction ? ["--single-transaction", "--exit-on-error"] : [],
121
- "--dbname",
122
- databaseNameFromUrl(databaseUrl),
123
- ...options.extraArgs ?? [],
124
- // POSIX end-of-options marker: `dumpPath` is the final positional
125
- // and must be interpreted as a path, not a flag. Without `--`, a
126
- // path that starts with `-` (e.g. a temp file generated as
127
- // `-tmp-XXX.dump`) would be misparsed by pg_restore as an unknown
128
- // option.
129
- "--",
130
- dumpPath
131
- ],
132
- { env: postgresEnvFromUrl(databaseUrl) }
133
- );
134
- }
135
- async function createPostgresDatabase(databaseUrl, options = {}) {
136
- const database = options.database ?? databaseNameFromUrl(databaseUrl);
137
- await runCommand(
138
- options.binary ?? "createdb",
139
- [database, ...options.extraArgs ?? []],
140
- {
141
- env: postgresEnvFromUrl(
142
- databaseUrl,
143
- options.maintenanceDatabase ?? "postgres"
144
- )
145
- }
146
- );
147
- }
148
- async function dropPostgresDatabase(databaseUrl, options = {}) {
149
- const database = options.database ?? databaseNameFromUrl(databaseUrl);
150
- await runCommand(
151
- options.binary ?? "dropdb",
152
- ["--if-exists", database, ...options.extraArgs ?? []],
153
- {
154
- env: postgresEnvFromUrl(
155
- databaseUrl,
156
- options.maintenanceDatabase ?? "postgres"
157
- )
158
- }
159
- );
160
- }
161
- async function runCommand(command, args, options = {}) {
162
- const parentEnv = { ...process.env };
163
- for (const key of LIBPQ_INHERITANCE_VARS) {
164
- delete parentEnv[key];
165
- }
166
- await new Promise((resolvePromise, reject) => {
167
- const child = spawn(command, args, {
168
- cwd: options.cwd ?? process.cwd(),
169
- env: { ...parentEnv, ...options.env },
170
- stdio: options.stdio ?? "inherit"
171
- });
172
- const stderrChunks = [];
173
- if (options.stdio === "pipe" && child.stderr) {
174
- child.stderr.on("data", (chunk) => {
175
- stderrChunks.push(chunk);
176
- });
177
- }
178
- child.on("error", reject);
179
- child.on("close", (code) => {
180
- if (code === 0) {
181
- resolvePromise();
182
- return;
183
- }
184
- const stderr = Buffer.concat(stderrChunks).toString("utf8").trim();
185
- const stderrSuffix = stderr ? `: ${stderr.slice(-2e3)}` : "";
186
- reject(new Error(`${command} exited with status ${code}${stderrSuffix}`));
187
- });
188
- });
189
- }
190
- function decodeUserInfo(value) {
191
- try {
192
- return decodeURIComponent(value);
193
- } catch {
194
- return value;
195
- }
196
- }
197
- export {
198
- assertCanExportDatabase as a,
199
- assertCanImportDatabase as b,
200
- createPostgresDatabase as c,
201
- databaseNameFromUrl as d,
202
- dropPostgresDatabase as e,
203
- dumpPostgresDatabase as f,
204
- restorePostgresDatabase as g,
205
- isLocalDatabaseUrl as i,
206
- postgresEnvFromUrl as p,
207
- redactDatabaseUrl as r
208
- };
209
- //# sourceMappingURL=postgres-cli-Cr6bBZ3q.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"postgres-cli-Cr6bBZ3q.js","sources":["../../src/postgres-cli.ts"],"sourcesContent":["/**\n * Shell-out wrappers for the postgres command-line tools (`pg_dump`,\n * `pg_restore`, `createdb`, `dropdb`) and the URL/locality helpers that\n * surround them.\n *\n * These live in `@happyvertical/sql` because postgres URL parsing and pg\n * binary invocation are SQL-layer concerns — no SMRT awareness or backup\n * orchestration here. See `@happyvertical/sql/backup` for the higher-level\n * snapshot helpers that compose these primitives with file storage.\n */\nimport { spawn } from 'node:child_process';\nimport { chmod, mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\n\nexport interface PostgresLocalityOptions {\n /** Allow exporting from a non-local database without --allow-production. */\n allowProduction?: boolean;\n /** Allow exporting a local database when `prod: true` is set. */\n allowLocal?: boolean;\n /** True when the caller is running a production-flavored export. */\n prod?: boolean;\n}\n\nexport interface PostgresImportLocalityOptions {\n allowProduction?: boolean;\n}\n\nexport interface DumpOptions {\n /** Extra args appended after the built-in pg_dump flags. */\n extraArgs?: string[];\n /** Override the binary name (e.g. `/usr/local/pg17/bin/pg_dump`). */\n binary?: string;\n}\n\nexport interface RestoreOptions {\n extraArgs?: string[];\n binary?: string;\n /**\n * Wrap the restore in `--single-transaction --exit-on-error` so a\n * mid-restore failure rolls the target database back to its prior\n * state instead of leaving it partially-restored-but-failing.\n * Defaults to `true`. Set to `false` if you need parallel restore\n * (`--jobs N` in `extraArgs`); pg_restore rejects `--single-transaction`\n * combined with `--jobs`.\n */\n singleTransaction?: boolean;\n}\n\nexport interface CreateDropOptions {\n /** Database name to drop. Defaults to the one parsed from the URL. */\n database?: string;\n /**\n * The maintenance database to connect to when running create/drop\n * (the target DB itself can't be open). Defaults to 'postgres'.\n */\n maintenanceDatabase?: string;\n extraArgs?: string[];\n binary?: string;\n}\n\n/**\n * Extract the database name from a postgres connection URL.\n *\n * Throws if the URL has no path/db segment (postgres rejects connections\n * without one anyway).\n */\nexport function databaseNameFromUrl(databaseUrl: string): string {\n const url = new URL(databaseUrl);\n const database = decodeURIComponent(url.pathname.replace(/^\\/+/u, ''));\n if (!database) throw new Error('Database URL must include a database name.');\n return database;\n}\n\n/**\n * Treat localhost / 127.0.0.1 / ::1 / empty-hostname URLs as \"local\".\n *\n * Used by the export/import safety guards to decide whether a command\n * needs `--allow-production` to proceed.\n */\nexport function isLocalDatabaseUrl(databaseUrl: string): boolean {\n try {\n const url = new URL(databaseUrl);\n const hostname = url.hostname.toLowerCase().replace(/^\\[|\\]$/gu, '');\n return (\n hostname === '' ||\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '::1'\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Strip credentials from a postgres URL for logging/manifest use.\n * Returns `[invalid database url]` if parsing fails.\n *\n * Redacts both the userinfo (`user:password@`) and any credential-shaped\n * query parameters (`?password=…`, `?passwd=…`, `?pass=…`) — cloud\n * providers like Neon and Supabase emit URLs with `?password=` instead of\n * (or in addition to) the userinfo form, and leaking those into logs or\n * the backup manifest defeats the rest of the redaction.\n */\nexport function redactDatabaseUrl(databaseUrl: string): string {\n try {\n const url = new URL(databaseUrl);\n if (url.username) url.username = '***';\n if (url.password) url.password = '***';\n for (const param of ['password', 'passwd', 'pass']) {\n if (url.searchParams.has(param)) {\n url.searchParams.set(param, '***');\n }\n }\n return url.toString();\n } catch {\n return '[invalid database url]';\n }\n}\n\n/**\n * Translate a postgres URL into the libpq env vars that pg_dump/pg_restore\n * read. Passing credentials this way keeps them out of process argv (and\n * therefore out of `ps`, audit logs, and error output).\n *\n * `databaseOverride` lets callers point pg tools at a different db on the\n * same server (e.g. connecting to `postgres` to drop the real target).\n */\nexport function postgresEnvFromUrl(\n databaseUrl: string,\n databaseOverride?: string,\n): Record<string, string> {\n const url = new URL(databaseUrl);\n if (url.protocol !== 'postgres:' && url.protocol !== 'postgresql:') {\n throw new Error(`Unsupported database URL protocol: ${url.protocol}`);\n }\n\n const env: Record<string, string> = {};\n const database = databaseOverride ?? databaseNameFromUrl(databaseUrl);\n\n // Only set vars we have URL-derived values for. Inherited libpq env\n // (PGHOST, PGSERVICE, etc.) is scrubbed separately by `runCommand`\n // via `LIBPQ_INHERITANCE_VARS` — see below. We cannot use empty\n // strings to \"unset\" these vars: libpq treats e.g. `PGSERVICE=''` as\n // a request for a service literally named empty-string, which fails\n // with `definition of service \"\" not found`. The right way to\n // \"unset\" is to remove the key entirely from the child's env, which\n // runCommand does for us before merging.\n env.PGDATABASE = database;\n if (url.hostname) {\n // Strip IPv6 brackets: `URL.hostname` returns `'[::1]'` for IPv6\n // literals, but libpq's `PGHOST` expects the bare address (`'::1'`).\n // Brackets are URI syntax only — passing them through means\n // pg_dump/pg_restore fail to resolve the host even though\n // `isLocalDatabaseUrl` correctly recognises the same URL as local.\n env.PGHOST = url.hostname.replace(/^\\[|\\]$/gu, '');\n }\n if (url.port) env.PGPORT = url.port;\n if (url.username) env.PGUSER = decodeUserInfo(url.username);\n\n // Password can come from userinfo OR query-string (`?password=...`,\n // `?passwd=...`, `?pass=...`) — cloud providers like Neon and\n // Supabase use the query-string form. `redactDatabaseUrl` already\n // masks all three in logs; the env builder honors all three for\n // connection.\n const passwordFromUrl =\n (url.password && decodeUserInfo(url.password)) ||\n url.searchParams.get('password') ||\n url.searchParams.get('passwd') ||\n url.searchParams.get('pass') ||\n '';\n if (passwordFromUrl) env.PGPASSWORD = passwordFromUrl;\n\n for (const [param, envName] of [\n ['sslmode', 'PGSSLMODE'],\n ['sslrootcert', 'PGSSLROOTCERT'],\n ['sslcert', 'PGSSLCERT'],\n ['sslkey', 'PGSSLKEY'],\n ] as const) {\n const value = url.searchParams.get(param);\n if (value) env[envName] = value;\n }\n\n return env;\n}\n\n/**\n * Libpq env vars that determine **where** a pg connection lands. Scrubbed\n * from the inherited parent environment by `runCommand` so a developer\n * with `PGHOST=staging` in their shell can't silently redirect a\n * pg_dump call that was supposed to target the URL the caller passed.\n *\n * SSL-related vars (PGSSLMODE/PGSSLROOTCERT/...) are intentionally NOT\n * scrubbed — a caller may legitimately want to inherit a system-wide\n * certificate path. They're explicitly overridden only when the URL\n * supplies a value.\n *\n * Auth/identity vars (PGUSER / PGPASSWORD / PGPASSFILE) are\n * intentionally NOT scrubbed: they don't change target routing and\n * some environments intentionally supply credentials and the\n * connecting role out-of-band while keeping DATABASE_URL itself\n * minimal — the Heroku/Railway/Render-style \"DATABASE_URL has the\n * host and database; PGUSER + PGPASSWORD env carry the auth identity\"\n * pattern. When the URL DOES supply a username or password,\n * `postgresEnvFromUrl` writes that value into the per-call env which\n * then overrides the inherited one via the spawn-env merge.\n *\n * `PGDATABASE` is also kept out of the scrub list: `postgresEnvFromUrl`\n * always sets it (either from the URL path or the explicit override),\n * so the parent's value is overwritten in the merge regardless.\n *\n * **Trade-off this opens up:** on a developer machine, a stale\n * `PGUSER`/`PGPASSWORD` set for an earlier task can flow into a later\n * `pg_dump` targeting a different database. This typically surfaces as\n * a clear authentication error rather than silent wrong-credential\n * use, but callers in environments where this is a real concern should\n * clear those env vars from `process.env` before invoking these\n * helpers (or supply the credential via the URL itself, which\n * overrides any inherited value).\n */\nconst LIBPQ_INHERITANCE_VARS = [\n 'PGHOST',\n 'PGHOSTADDR',\n 'PGPORT',\n 'PGSERVICE',\n 'PGSERVICEFILE',\n] as const;\n\n/**\n * Guard for export operations. Two distinct hazards:\n * - running a \"prod\" export against a local DB by mistake (likely a\n * developer running prod scripts on their laptop)\n * - running a regular export against a non-local DB (likely a developer\n * pointing at staging or prod when they meant to target their laptop)\n *\n * Each escape hatch is named so the override has to be deliberate.\n */\nexport function assertCanExportDatabase(\n databaseUrl: string,\n options: PostgresLocalityOptions,\n): void {\n const local = isLocalDatabaseUrl(databaseUrl);\n if (options.prod && local && !options.allowLocal) {\n throw new Error(\n 'Refusing to run a production-flavored export against a local database. Pass allowLocal only when intentionally testing the production export path.',\n );\n }\n if (!options.prod && !local && !options.allowProduction) {\n throw new Error(\n 'Refusing to export a non-local database without allowProduction. Use the production export path, or pass allowProduction intentionally.',\n );\n }\n}\n\n/**\n * Guard for import/restore operations against non-local databases.\n * Restoring is destructive, so the default is \"local only\".\n */\nexport function assertCanImportDatabase(\n databaseUrl: string,\n options: PostgresImportLocalityOptions,\n): void {\n if (!isLocalDatabaseUrl(databaseUrl) && !options.allowProduction) {\n throw new Error(\n 'Refusing to import into a non-local database without allowProduction.',\n );\n }\n}\n\n/**\n * Run `pg_dump` against `databaseUrl`, writing a custom-format archive to\n * `dumpPath`. Defaults match the common \"logical backup, no-owner, no-acl\"\n * recipe used for cross-environment restores.\n *\n * Credentials travel via env vars, never argv.\n */\nexport async function dumpPostgresDatabase(\n databaseUrl: string,\n dumpPath: string,\n options: DumpOptions = {},\n): Promise<void> {\n await mkdir(dirname(dumpPath), { recursive: true, mode: 0o700 });\n await runCommand(\n options.binary ?? 'pg_dump',\n [\n '--format=custom',\n '--no-owner',\n '--no-acl',\n '--file',\n dumpPath,\n ...(options.extraArgs ?? []),\n ],\n { env: postgresEnvFromUrl(databaseUrl) },\n );\n await chmod(dumpPath, 0o600);\n}\n\n/**\n * Run `pg_restore` against `databaseUrl` from a custom-format archive at\n * `dumpPath`. Uses `--clean --if-exists` so the target db can be a previous\n * state of the same schema.\n */\nexport async function restorePostgresDatabase(\n databaseUrl: string,\n dumpPath: string,\n options: RestoreOptions = {},\n): Promise<void> {\n const singleTransaction = options.singleTransaction ?? true;\n await runCommand(\n options.binary ?? 'pg_restore',\n [\n '--clean',\n '--if-exists',\n '--no-owner',\n '--no-acl',\n // Atomic-restore default: wrap the whole operation in one\n // transaction. Without this, a mid-restore failure (e.g. a unique\n // constraint conflict halfway through data load) leaves the\n // target database with the `--clean` DROPs applied AND part of\n // the new schema/data, while pg_restore still exits non-zero —\n // operationally the worst of both worlds. Caller can opt out via\n // `singleTransaction: false` when running parallel restores\n // (`--jobs N`) since pg_restore rejects the combination.\n ...(singleTransaction ? ['--single-transaction', '--exit-on-error'] : []),\n '--dbname',\n databaseNameFromUrl(databaseUrl),\n ...(options.extraArgs ?? []),\n // POSIX end-of-options marker: `dumpPath` is the final positional\n // and must be interpreted as a path, not a flag. Without `--`, a\n // path that starts with `-` (e.g. a temp file generated as\n // `-tmp-XXX.dump`) would be misparsed by pg_restore as an unknown\n // option.\n '--',\n dumpPath,\n ],\n { env: postgresEnvFromUrl(databaseUrl) },\n );\n}\n\n/**\n * `createdb`-equivalent. Connects via the maintenance database (default\n * `postgres`) and creates the database named in the URL, or in\n * `options.database` if provided.\n */\nexport async function createPostgresDatabase(\n databaseUrl: string,\n options: CreateDropOptions = {},\n): Promise<void> {\n const database = options.database ?? databaseNameFromUrl(databaseUrl);\n await runCommand(\n options.binary ?? 'createdb',\n [database, ...(options.extraArgs ?? [])],\n {\n env: postgresEnvFromUrl(\n databaseUrl,\n options.maintenanceDatabase ?? 'postgres',\n ),\n },\n );\n}\n\n/**\n * `dropdb`-equivalent, with `--if-exists` by default so callers can use\n * this idempotently as part of a reset flow.\n */\nexport async function dropPostgresDatabase(\n databaseUrl: string,\n options: CreateDropOptions = {},\n): Promise<void> {\n const database = options.database ?? databaseNameFromUrl(databaseUrl);\n await runCommand(\n options.binary ?? 'dropdb',\n ['--if-exists', database, ...(options.extraArgs ?? [])],\n {\n env: postgresEnvFromUrl(\n databaseUrl,\n options.maintenanceDatabase ?? 'postgres',\n ),\n },\n );\n}\n\n/**\n * Spawn helper used by the wrappers above. Inherits stdio so progress and\n * error output stream to the parent terminal (these are interactive ops),\n * unless the caller passes `stdio: 'pipe'` for programmatic use — in\n * which case stderr is captured and included in the thrown error so the\n * failure isn't an opaque `\"pg_dump exited with status 1\"`.\n *\n * Libpq connection vars (PGHOST, PGSERVICE, ...) inherited from the\n * parent process are scrubbed before merging with `options.env`. This is\n * the half of \"URL-determined connection target\" that\n * `postgresEnvFromUrl` can't do alone: without scrubbing, a developer\n * with `PGHOST=staging` in their shell would silently redirect the\n * child's connection regardless of what the URL specified.\n */\nexport async function runCommand(\n command: string,\n args: string[],\n options: {\n cwd?: string;\n env?: Record<string, string>;\n stdio?: 'inherit' | 'pipe';\n } = {},\n): Promise<void> {\n const parentEnv = { ...process.env };\n for (const key of LIBPQ_INHERITANCE_VARS) {\n delete parentEnv[key];\n }\n\n await new Promise<void>((resolvePromise, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd ?? process.cwd(),\n env: { ...parentEnv, ...options.env },\n stdio: options.stdio ?? 'inherit',\n });\n\n // When the caller pipes stdio, capture stderr so we can surface it\n // in the rejection. Default (`'inherit'`) streams stderr to the\n // parent terminal live; there's nothing to capture in that case.\n const stderrChunks: Buffer[] = [];\n if (options.stdio === 'pipe' && child.stderr) {\n child.stderr.on('data', (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n }\n\n child.on('error', reject);\n child.on('close', (code) => {\n if (code === 0) {\n resolvePromise();\n return;\n }\n const stderr = Buffer.concat(stderrChunks).toString('utf8').trim();\n const stderrSuffix = stderr ? `: ${stderr.slice(-2000)}` : '';\n reject(new Error(`${command} exited with status ${code}${stderrSuffix}`));\n });\n });\n}\n\nfunction decodeUserInfo(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n"],"names":[],"mappings":"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"}