@codemarc/blt 1.10.1 → 1.10.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.
Files changed (45) hide show
  1. package/README.md +83 -0
  2. package/dist/blt +2 -0
  3. package/dist/blt.d.ts.map +1 -1
  4. package/dist/blt.js.map +1 -1
  5. package/dist/commands/db/diff-endpoint.d.ts +16 -0
  6. package/dist/commands/db/diff-endpoint.d.ts.map +1 -0
  7. package/dist/commands/db/diff-endpoint.js +39 -0
  8. package/dist/commands/db/diff-endpoint.js.map +1 -0
  9. package/dist/commands/db/diff.d.ts +37 -0
  10. package/dist/commands/db/diff.d.ts.map +1 -0
  11. package/dist/commands/db/diff.js +123 -0
  12. package/dist/commands/db/diff.js.map +1 -0
  13. package/dist/commands/db/dump.d.ts +23 -0
  14. package/dist/commands/db/dump.d.ts.map +1 -0
  15. package/dist/commands/db/dump.js +49 -0
  16. package/dist/commands/db/dump.js.map +1 -0
  17. package/dist/commands/db/env-url.d.ts +4 -0
  18. package/dist/commands/db/env-url.d.ts.map +1 -0
  19. package/dist/commands/db/env-url.js +34 -0
  20. package/dist/commands/db/env-url.js.map +1 -0
  21. package/dist/commands/db/patch.d.ts +14 -0
  22. package/dist/commands/db/patch.d.ts.map +1 -0
  23. package/dist/commands/db/patch.js +58 -0
  24. package/dist/commands/db/patch.js.map +1 -0
  25. package/dist/commands/db/run.d.ts +4 -0
  26. package/dist/commands/db/run.d.ts.map +1 -0
  27. package/dist/commands/db/run.js +19 -0
  28. package/dist/commands/db/run.js.map +1 -0
  29. package/dist/commands/db/schema-loader.d.ts +28 -0
  30. package/dist/commands/db/schema-loader.d.ts.map +1 -0
  31. package/dist/commands/db/schema-loader.js +121 -0
  32. package/dist/commands/db/schema-loader.js.map +1 -0
  33. package/dist/commands/db/sql.d.ts +10 -0
  34. package/dist/commands/db/sql.d.ts.map +1 -0
  35. package/dist/commands/db/sql.js +152 -0
  36. package/dist/commands/db/sql.js.map +1 -0
  37. package/dist/commands/db/supabase-schema.d.ts +38 -0
  38. package/dist/commands/db/supabase-schema.d.ts.map +1 -0
  39. package/dist/commands/db/supabase-schema.js +132 -0
  40. package/dist/commands/db/supabase-schema.js.map +1 -0
  41. package/dist/commands/db.d.ts +3 -0
  42. package/dist/commands/db.d.ts.map +1 -0
  43. package/dist/commands/db.js +116 -0
  44. package/dist/commands/db.js.map +1 -0
  45. package/package.json +6 -2
@@ -0,0 +1,28 @@
1
+ import type { Logger } from "@caporal/core";
2
+ export type SchemaUrlPair = {
3
+ sourceUrl: string;
4
+ targetUrl: string;
5
+ cleanup: () => void;
6
+ };
7
+ /**
8
+ * Load one or two schema dump files into a temporary Postgres (Docker) so
9
+ * `supabase db diff` can compare them via connection URLs.
10
+ */
11
+ export declare function resolveSchemaUrlsForDiff(opts: {
12
+ source: {
13
+ kind: "env";
14
+ dbUrl: string;
15
+ } | {
16
+ kind: "file";
17
+ path: string;
18
+ };
19
+ target: {
20
+ kind: "env";
21
+ dbUrl: string;
22
+ } | {
23
+ kind: "file";
24
+ path: string;
25
+ };
26
+ logger: Logger;
27
+ }): SchemaUrlPair;
28
+ //# sourceMappingURL=schema-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-loader.d.ts","sourceRoot":"","sources":["../../../src/commands/db/schema-loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAK5C,MAAM,MAAM,aAAa,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAgEF;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC9C,MAAM,EAAE;QAAE,IAAI,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE,MAAM,EAAE;QAAE,IAAI,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE,MAAM,EAAE,MAAM,CAAC;CACf,GAAG,aAAa,CAkFhB"}
@@ -0,0 +1,121 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { spawnSync } from "node:child_process";
3
+ const PG_IMAGE = "postgres:16";
4
+ const PG_PASSWORD = "blt_diff_temp";
5
+ function dockerAvailable() {
6
+ const result = spawnSync("docker", ["version"], { encoding: "utf8" });
7
+ return !result.error && (result.status ?? 1) === 0;
8
+ }
9
+ function requireDocker(logger) {
10
+ if (!dockerAvailable()) {
11
+ logger.error("Docker is required when diffing from .sql file paths.\n" +
12
+ " Install Docker or pass trailz env names instead of .sql files.");
13
+ process.exit(1);
14
+ }
15
+ }
16
+ function runDocker(args, logger, opts = {}) {
17
+ const result = spawnSync("docker", args, {
18
+ encoding: "utf8",
19
+ input: opts.input,
20
+ maxBuffer: 64 * 1024 * 1024,
21
+ });
22
+ if (result.error) {
23
+ throw result.error;
24
+ }
25
+ if ((result.status ?? 1) !== 0) {
26
+ const detail = [result.stderr, result.stdout].filter(Boolean).join("\n").trim();
27
+ throw new Error(`docker ${args.join(" ")} failed${detail ? `: ${detail}` : ""}`);
28
+ }
29
+ return result.stdout ?? "";
30
+ }
31
+ function waitForPostgres(containerName, logger) {
32
+ for (let attempt = 0; attempt < 30; attempt++) {
33
+ const result = spawnSync("docker", ["exec", containerName, "pg_isready", "-U", "postgres"], { encoding: "utf8" });
34
+ if ((result.status ?? 1) === 0) {
35
+ return;
36
+ }
37
+ spawnSync("sleep", ["1"]);
38
+ }
39
+ logger.error("Timed out waiting for temporary Postgres container.");
40
+ process.exit(1);
41
+ }
42
+ function parsePublishedPort(dockerPortOutput) {
43
+ const match = dockerPortOutput.trim().match(/:(\d+)$/);
44
+ if (!match) {
45
+ throw new Error(`Could not parse docker port mapping: ${dockerPortOutput}`);
46
+ }
47
+ return Number(match[1]);
48
+ }
49
+ function dbUrl(hostPort, database) {
50
+ return `postgresql://postgres:${PG_PASSWORD}@127.0.0.1:${hostPort}/${database}`;
51
+ }
52
+ /**
53
+ * Load one or two schema dump files into a temporary Postgres (Docker) so
54
+ * `supabase db diff` can compare them via connection URLs.
55
+ */
56
+ export function resolveSchemaUrlsForDiff(opts) {
57
+ if (opts.source.kind === "env" && opts.target.kind === "env") {
58
+ return {
59
+ sourceUrl: opts.source.dbUrl,
60
+ targetUrl: opts.target.dbUrl,
61
+ cleanup: () => { },
62
+ };
63
+ }
64
+ requireDocker(opts.logger);
65
+ const containerName = `blt-db-diff-${process.pid}`;
66
+ let stopped = false;
67
+ const cleanup = () => {
68
+ if (stopped)
69
+ return;
70
+ stopped = true;
71
+ spawnSync("docker", ["rm", "-f", containerName], { encoding: "utf8" });
72
+ };
73
+ try {
74
+ opts.logger.info("Starting temporary Postgres container for .sql schema diff…");
75
+ runDocker([
76
+ "run",
77
+ "-d",
78
+ "--rm",
79
+ "--name",
80
+ containerName,
81
+ "-e",
82
+ `POSTGRES_PASSWORD=${PG_PASSWORD}`,
83
+ "-p",
84
+ "127.0.0.1::5432",
85
+ PG_IMAGE,
86
+ ], opts.logger);
87
+ const portOutput = runDocker(["port", containerName, "5432"], opts.logger);
88
+ const hostPort = parsePublishedPort(portOutput);
89
+ waitForPostgres(containerName, opts.logger);
90
+ const ensureLoaded = (database, sqlPath, label) => {
91
+ opts.logger.info(`Loading ${label} schema from ${sqlPath}…`);
92
+ runDocker(["exec", containerName, "createdb", "-U", "postgres", database], opts.logger);
93
+ const sql = readFileSync(sqlPath, "utf8");
94
+ runDocker([
95
+ "exec",
96
+ "-i",
97
+ containerName,
98
+ "psql",
99
+ "-U",
100
+ "postgres",
101
+ "-d",
102
+ database,
103
+ "-v",
104
+ "ON_ERROR_STOP=1",
105
+ ], opts.logger, { input: sql });
106
+ return dbUrl(hostPort, database);
107
+ };
108
+ const sourceUrl = opts.source.kind === "env"
109
+ ? opts.source.dbUrl
110
+ : ensureLoaded("blt_source", opts.source.path, "source");
111
+ const targetUrl = opts.target.kind === "env"
112
+ ? opts.target.dbUrl
113
+ : ensureLoaded("blt_target", opts.target.path, "target");
114
+ return { sourceUrl, targetUrl, cleanup };
115
+ }
116
+ catch (error) {
117
+ cleanup();
118
+ throw error;
119
+ }
120
+ }
121
+ //# sourceMappingURL=schema-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-loader.js","sourceRoot":"","sources":["../../../src/commands/db/schema-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { Logger } from "@caporal/core";
2
+ export type DbSqlFormat = "table" | "json" | "jsonl" | "toon" | "csv";
3
+ export type DbSqlOptions = {
4
+ verbose?: boolean;
5
+ format?: DbSqlFormat;
6
+ /** Suppress connection progress (auto when stdout is piped for structured formats). */
7
+ quiet?: boolean;
8
+ };
9
+ export declare function dbSql(sql: string, options: DbSqlOptions, logger: Logger): Promise<void>;
10
+ //# sourceMappingURL=sql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../../src/commands/db/sql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAM5C,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAEtE,MAAM,MAAM,YAAY,GAAG;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,uFAAuF;IACvF,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAyHF,wBAAsB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkD7F"}
@@ -0,0 +1,152 @@
1
+ import { encode } from "@toon-format/toon";
2
+ import pg from "pg";
3
+ import { getLoadConnectionString } from "../../lib/database-runner";
4
+ import { describeSqlStatement, splitSqlStatements } from "../../lib/split-sql-statements";
5
+ let stdoutEpipeInstalled = false;
6
+ function isStructuredFormat(format) {
7
+ return format === "json" || format === "jsonl" || format === "toon" || format === "csv";
8
+ }
9
+ function installStdoutEpipeHandler() {
10
+ if (stdoutEpipeInstalled)
11
+ return;
12
+ stdoutEpipeInstalled = true;
13
+ process.stdout.on("error", (error) => {
14
+ if (error.code === "EPIPE") {
15
+ process.exit(0);
16
+ }
17
+ });
18
+ }
19
+ function writeStdout(line) {
20
+ process.stdout.write(`${line}\n`);
21
+ }
22
+ function formatCell(value) {
23
+ if (value === null || value === undefined)
24
+ return "";
25
+ if (typeof value === "object")
26
+ return JSON.stringify(value);
27
+ return String(value);
28
+ }
29
+ function escapeCsvCell(value) {
30
+ const text = formatCell(value);
31
+ if (/[",\r\n]/.test(text)) {
32
+ return `"${text.replace(/"/g, '""')}"`;
33
+ }
34
+ return text;
35
+ }
36
+ function renderTable(rows, fields) {
37
+ if (rows.length === 0) {
38
+ writeStdout("(0 rows)");
39
+ return;
40
+ }
41
+ const headers = fields;
42
+ const tableRows = [headers];
43
+ for (const row of rows) {
44
+ tableRows.push(headers.map((h) => formatCell(row[h])));
45
+ }
46
+ const colWidths = headers.map((_header, i) => Math.max(...tableRows.map((row) => row[i].length)));
47
+ const renderRow = (row) => `| ${row.map((cell, i) => cell.padEnd(colWidths[i])).join(" | ")} |`;
48
+ const renderDivider = () => `|-${colWidths.map((w) => "-".repeat(w)).join("-|-")}-|`;
49
+ writeStdout(renderRow(tableRows[0]));
50
+ writeStdout(renderDivider());
51
+ for (let i = 1; i < tableRows.length; i++) {
52
+ writeStdout(renderRow(tableRows[i]));
53
+ }
54
+ writeStdout(`\n(${rows.length} row${rows.length === 1 ? "" : "s"})`);
55
+ }
56
+ function renderCsv(rows, fields) {
57
+ writeStdout(fields.map(escapeCsvCell).join(","));
58
+ for (const row of rows) {
59
+ writeStdout(fields.map((field) => escapeCsvCell(row[field])).join(","));
60
+ }
61
+ }
62
+ function renderJsonl(rows) {
63
+ for (const row of rows) {
64
+ writeStdout(JSON.stringify(row));
65
+ }
66
+ }
67
+ function printQueryResult(result, options, context) {
68
+ const prefix = context?.statementIndex !== undefined
69
+ ? `[${context.statementIndex + 1}] ${context.statementLabel ?? "statement"}: `
70
+ : "";
71
+ if (result.fields.length > 0) {
72
+ const fields = result.fields.map((f) => f.name);
73
+ if (options.format === "json") {
74
+ writeStdout(prefix + JSON.stringify(result.rows, null, 2));
75
+ }
76
+ else if (options.format === "jsonl") {
77
+ if (prefix)
78
+ writeStdout(prefix);
79
+ renderJsonl(result.rows);
80
+ }
81
+ else if (options.format === "toon") {
82
+ writeStdout(prefix + encode(result.rows));
83
+ }
84
+ else if (options.format === "csv") {
85
+ if (prefix)
86
+ writeStdout(prefix);
87
+ renderCsv(result.rows, fields);
88
+ }
89
+ else {
90
+ if (prefix)
91
+ writeStdout(prefix);
92
+ renderTable(result.rows, fields);
93
+ }
94
+ return;
95
+ }
96
+ const affected = result.rowCount ?? 0;
97
+ writeStdout(`${prefix}OK — ${affected} row${affected === 1 ? "" : "s"} affected`);
98
+ }
99
+ async function executeOne(client, sql, options, context) {
100
+ const result = await client.query(sql);
101
+ printQueryResult(result, options, context);
102
+ }
103
+ export async function dbSql(sql, options, logger) {
104
+ const trimmed = sql.trim();
105
+ if (!trimmed) {
106
+ logger.error("SQL string is empty");
107
+ process.exit(1);
108
+ }
109
+ installStdoutEpipeHandler();
110
+ const quiet = options.quiet === true ||
111
+ (!process.stdout.isTTY && isStructuredFormat(options.format));
112
+ const connectionString = getLoadConnectionString();
113
+ const client = new pg.Client({ connectionString });
114
+ try {
115
+ if (!quiet) {
116
+ logger.info("Connecting to database…");
117
+ }
118
+ await client.connect();
119
+ if (options.verbose) {
120
+ const statements = splitSqlStatements(trimmed);
121
+ if (statements.length === 0) {
122
+ logger.error("No SQL statements found");
123
+ process.exit(1);
124
+ }
125
+ if (!quiet) {
126
+ logger.info(`Executing ${statements.length} statement(s)…`);
127
+ }
128
+ for (let i = 0; i < statements.length; i++) {
129
+ const stmt = statements[i];
130
+ if (!stmt)
131
+ continue;
132
+ const label = describeSqlStatement(stmt, i);
133
+ await executeOne(client, stmt, options, {
134
+ statementIndex: i,
135
+ statementLabel: label,
136
+ });
137
+ }
138
+ }
139
+ else {
140
+ await executeOne(client, trimmed, options);
141
+ }
142
+ }
143
+ catch (error) {
144
+ const message = error instanceof Error ? error.message : String(error);
145
+ logger.error(`SQL failed: ${message}`);
146
+ process.exit(1);
147
+ }
148
+ finally {
149
+ await client.end();
150
+ }
151
+ }
152
+ //# sourceMappingURL=sql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.js","sourceRoot":"","sources":["../../../src/commands/db/sql.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAW1F,IAAI,oBAAoB,GAAG,KAAK,CAAC;AAEjC,SAAS,kBAAkB,CAAC,MAA+B;IAC1D,OAAO,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,KAAK,CAAC;AACzF,CAAC;AAED,SAAS,yBAAyB;IACjC,IAAI,oBAAoB;QAAE,OAAO;IACjC,oBAAoB,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAA4B,EAAE,EAAE;QAC3D,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IACjC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACrD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5D,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACtB,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACpC,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,WAAW,CAAC,IAA+B,EAAE,MAAgB;IACrE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,WAAW,CAAC,UAAU,CAAC,CAAC;QACxB,OAAO;IACR,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC;IACvB,MAAM,SAAS,GAAe,CAAC,OAAO,CAAC,CAAC;IACxC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CAC5C,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAClD,CAAC;IAEF,MAAM,SAAS,GAAG,CAAC,GAAa,EAAE,EAAE,CACnC,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACtE,MAAM,aAAa,GAAG,GAAG,EAAE,CAC1B,KAAK,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IAE1D,WAAW,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,WAAW,CAAC,aAAa,EAAE,CAAC,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,WAAW,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC;IACD,WAAW,CAAC,MAAM,IAAI,CAAC,MAAM,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;AACtE,CAAC;AAED,SAAS,SAAS,CAAC,IAA+B,EAAE,MAAgB;IACnE,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACjD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACzE,CAAC;AACF,CAAC;AAED,SAAS,WAAW,CAAC,IAA+B;IACnD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IAClC,CAAC;AACF,CAAC;AAED,SAAS,gBAAgB,CACxB,MAAsB,EACtB,OAAqB,EACrB,OAA8D;IAE9D,MAAM,MAAM,GACX,OAAO,EAAE,cAAc,KAAK,SAAS;QACpC,CAAC,CAAC,IAAI,OAAO,CAAC,cAAc,GAAG,CAAC,KAAK,OAAO,CAAC,cAAc,IAAI,WAAW,IAAI;QAC9E,CAAC,CAAC,EAAE,CAAC;IAEP,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC/B,WAAW,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5D,CAAC;aAAM,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YACvC,IAAI,MAAM;gBAAE,WAAW,CAAC,MAAM,CAAC,CAAC;YAChC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;aAAM,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YACtC,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YACrC,IAAI,MAAM;gBAAE,WAAW,CAAC,MAAM,CAAC,CAAC;YAChC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACP,IAAI,MAAM;gBAAE,WAAW,CAAC,MAAM,CAAC,CAAC;YAChC,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAClC,CAAC;QACD,OAAO;IACR,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;IACtC,WAAW,CAAC,GAAG,MAAM,QAAQ,QAAQ,OAAO,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC;AACnF,CAAC;AAED,KAAK,UAAU,UAAU,CACxB,MAAiB,EACjB,GAAW,EACX,OAAqB,EACrB,OAA8D;IAE9D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACvC,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,GAAW,EAAE,OAAqB,EAAE,MAAc;IAC7E,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IAED,yBAAyB,EAAE,CAAC;IAE5B,MAAM,KAAK,GACV,OAAO,CAAC,KAAK,KAAK,IAAI;QACtB,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAE/D,MAAM,gBAAgB,GAAG,uBAAuB,EAAE,CAAC;IACnD,MAAM,MAAM,GAAG,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAEnD,IAAI,CAAC;QACJ,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACxC,CAAC;QACD,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QAEvB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACrB,MAAM,UAAU,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAC/C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;gBACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjB,CAAC;YACD,IAAI,CAAC,KAAK,EAAE,CAAC;gBACZ,MAAM,CAAC,IAAI,CAAC,aAAa,UAAU,CAAC,MAAM,gBAAgB,CAAC,CAAC;YAC7D,CAAC;YACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5C,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;gBAC3B,IAAI,CAAC,IAAI;oBAAE,SAAS;gBACpB,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC5C,MAAM,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE;oBACvC,cAAc,EAAE,CAAC;oBACjB,cAAc,EAAE,KAAK;iBACrB,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;aAAM,CAAC;YACP,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;IACF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,MAAM,CAAC,KAAK,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;YAAS,CAAC;QACV,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC;IACpB,CAAC;AACF,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { Logger } from "@caporal/core";
2
+ export declare function resolveOutDir(dir: string, cwd: string): string;
3
+ /**
4
+ * Fix common trailz / pooler URL shapes and prepare for Supabase CLI.
5
+ * The CLI expects percent-encoded postgres URLs; bare `?` / `&` in paths breaks parsing
6
+ * (e.g. database name `postgres&sslmode=require`).
7
+ */
8
+ export declare function normalizePostgresConnectionString(connectionString: string): string;
9
+ /** Normalize trailz pooler URLs for `supabase db dump` / `db diff` (do not fully percent-encode the URL). */
10
+ export declare function preparePostgresUrlForSupabaseCli(connectionString: string): string;
11
+ export declare function buildSupabaseDumpArgs(dbUrl: string, schema: string, outputFile: string): string[];
12
+ export declare function buildSupabaseDiffArgs(fromUrl: string, toUrl: string, schema: string, outputFile: string): string[];
13
+ export type SqlFileKind = "dump" | "patch";
14
+ /** Normalize comma-separated schema flags (e.g. `public, auth` → `public,auth`). */
15
+ export declare function normalizeSchemaOption(schema: string): string;
16
+ export declare function sqlFileHeader(opts: {
17
+ command: "dump" | "patch";
18
+ kind: SqlFileKind;
19
+ env: string;
20
+ otherEnv?: string;
21
+ schema: string;
22
+ generatedAt: string;
23
+ }): string;
24
+ export declare function requireSupabaseCli(logger: Logger): void;
25
+ export declare function prependHeader(path: string, header: string): void;
26
+ export declare function fileBytes(path: string): number;
27
+ export declare function ensureOutDir(outDir: string, logger: Logger): void;
28
+ /** Run `supabase db dump` and prepend a review header. */
29
+ export declare function runSchemaDump(opts: {
30
+ dbUrl: string;
31
+ schema: string;
32
+ outputFile: string;
33
+ header: string;
34
+ logger: Logger;
35
+ cwd: string;
36
+ label?: string;
37
+ }): void;
38
+ //# sourceMappingURL=supabase-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase-schema.d.ts","sourceRoot":"","sources":["../../../src/commands/db/supabase-schema.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAG5C,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CA8BlF;AAED,6GAA6G;AAC7G,wBAAgB,gCAAgC,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GAChB,MAAM,EAAE,CAWV;AAED,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GAChB,MAAM,EAAE,CAaV;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3C,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAM5D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE;IACnC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAkBT;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CASvD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAQhE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM9C;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAGjE;AAED,0DAA0D;AAC1D,wBAAgB,aAAa,CAAC,IAAI,EAAE;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,IAAI,CAWP"}
@@ -0,0 +1,132 @@
1
+ import { mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
2
+ import { isAbsolute, resolve } from "node:path";
3
+ import { spawnSync } from "node:child_process";
4
+ import { runCommand } from "../app/shell";
5
+ export function resolveOutDir(dir, cwd) {
6
+ return isAbsolute(dir) ? dir : resolve(cwd, dir);
7
+ }
8
+ /**
9
+ * Fix common trailz / pooler URL shapes and prepare for Supabase CLI.
10
+ * The CLI expects percent-encoded postgres URLs; bare `?` / `&` in paths breaks parsing
11
+ * (e.g. database name `postgres&sslmode=require`).
12
+ */
13
+ export function normalizePostgresConnectionString(connectionString) {
14
+ const trimmed = connectionString.trim();
15
+ try {
16
+ const fixed = trimmed.replace(/\/postgres&/i, "/postgres?");
17
+ const url = new URL(fixed);
18
+ const dbSegment = url.pathname.replace(/^\//, "").split("/")[0] ?? "postgres";
19
+ const dbName = dbSegment.split("?")[0]?.split("&")[0] || "postgres";
20
+ url.pathname = `/${dbName}`;
21
+ // Recover params accidentally fused into the path segment
22
+ const fused = dbSegment.includes("&") ? dbSegment.slice(dbName.length) : "";
23
+ if (fused.startsWith("&")) {
24
+ for (const part of fused.slice(1).split("&")) {
25
+ const [key, value] = part.split("=");
26
+ if (key)
27
+ url.searchParams.set(key, value ?? "");
28
+ }
29
+ }
30
+ if (!url.searchParams.has("sslmode") &&
31
+ url.hostname !== "127.0.0.1" &&
32
+ url.hostname !== "localhost") {
33
+ url.searchParams.set("sslmode", "require");
34
+ }
35
+ return url.toString();
36
+ }
37
+ catch {
38
+ return trimmed;
39
+ }
40
+ }
41
+ /** Normalize trailz pooler URLs for `supabase db dump` / `db diff` (do not fully percent-encode the URL). */
42
+ export function preparePostgresUrlForSupabaseCli(connectionString) {
43
+ return normalizePostgresConnectionString(connectionString);
44
+ }
45
+ export function buildSupabaseDumpArgs(dbUrl, schema, outputFile) {
46
+ return [
47
+ "db",
48
+ "dump",
49
+ "--db-url",
50
+ preparePostgresUrlForSupabaseCli(dbUrl),
51
+ "--schema",
52
+ schema,
53
+ "-f",
54
+ outputFile,
55
+ ];
56
+ }
57
+ export function buildSupabaseDiffArgs(fromUrl, toUrl, schema, outputFile) {
58
+ return [
59
+ "db",
60
+ "diff",
61
+ "--from",
62
+ preparePostgresUrlForSupabaseCli(fromUrl),
63
+ "--to",
64
+ preparePostgresUrlForSupabaseCli(toUrl),
65
+ "--schema",
66
+ schema,
67
+ "--output",
68
+ outputFile,
69
+ ];
70
+ }
71
+ /** Normalize comma-separated schema flags (e.g. `public, auth` → `public,auth`). */
72
+ export function normalizeSchemaOption(schema) {
73
+ return schema
74
+ .split(",")
75
+ .map((part) => part.trim())
76
+ .filter(Boolean)
77
+ .join(",");
78
+ }
79
+ export function sqlFileHeader(opts) {
80
+ const purpose = opts.kind === "patch"
81
+ ? "Apply to TARGET so its schema matches SOURCE."
82
+ : "Schema dump for manual review.";
83
+ const envLines = opts.command === "patch"
84
+ ? `-- source env: ${opts.env}\n-- target env: ${opts.otherEnv ?? ""}\n`
85
+ : `-- env: ${opts.env}\n`;
86
+ return `-- BLT db ${opts.command} (${opts.kind})
87
+ ${envLines}-- schema: ${opts.schema}
88
+ -- generated: ${opts.generatedAt}
89
+ -- purpose: ${purpose}
90
+ -- WARNING: Review before apply. Generated SQL is not auto-approved production SQL.
91
+
92
+ `;
93
+ }
94
+ export function requireSupabaseCli(logger) {
95
+ const result = spawnSync("supabase", ["--version"], { encoding: "utf8" });
96
+ if (result.error || (result.status ?? 1) !== 0) {
97
+ logger.error("supabase CLI not found on PATH.\n" +
98
+ " Install: https://supabase.com/docs/guides/cli");
99
+ process.exit(1);
100
+ }
101
+ }
102
+ export function prependHeader(path, header) {
103
+ let body = "";
104
+ try {
105
+ body = readFileSync(path, "utf8");
106
+ }
107
+ catch {
108
+ body = "";
109
+ }
110
+ writeFileSync(path, header + body, "utf8");
111
+ }
112
+ export function fileBytes(path) {
113
+ try {
114
+ return statSync(path).size;
115
+ }
116
+ catch {
117
+ return 0;
118
+ }
119
+ }
120
+ export function ensureOutDir(outDir, logger) {
121
+ mkdirSync(outDir, { recursive: true });
122
+ logger.info(`Output directory: ${outDir}`);
123
+ }
124
+ /** Run `supabase db dump` and prepend a review header. */
125
+ export function runSchemaDump(opts) {
126
+ if (opts.label) {
127
+ opts.logger.info(opts.label);
128
+ }
129
+ runCommand("supabase", buildSupabaseDumpArgs(opts.dbUrl, opts.schema, opts.outputFile), opts.logger, { cwd: opts.cwd });
130
+ prependHeader(opts.outputFile, opts.header);
131
+ }
132
+ //# sourceMappingURL=supabase-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase-schema.js","sourceRoot":"","sources":["../../../src/commands/db/supabase-schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Program } from "@caporal/core";
2
+ export default function dbCommand(program: Program): void;
3
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/commands/db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiC,OAAO,EAAE,MAAM,eAAe,CAAC;AAwB5E,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,OAAO,EAAE,OAAO,QA4IjD"}
@@ -0,0 +1,116 @@
1
+ import { dbDump } from "./db/dump";
2
+ import { dbPatch, DEFAULT_PATCH_NAME } from "./db/patch";
3
+ import { dbRun } from "./db/run";
4
+ import { dbSql } from "./db/sql";
5
+ const dbHelpText = `
6
+ database utilities
7
+
8
+ Usage:
9
+ blt db <operation>
10
+
11
+ Available operations:
12
+ sql <query> Execute a sql string against the load database
13
+ run <file> Execute a .sql file against the load database
14
+ dump <env> Dump schema from a trailz env to SQL
15
+ patch <source> <target> Write a single roll-forward patch SQL file (does not apply)
16
+ Source/target: trailz env name or path to .sql dump
17
+
18
+ Uses SUPABASE_CONNECTION_STRING (or BLT_DATA_LOAD_URL for sql/run).
19
+
20
+ Run 'blt db <operation> --help' for more information.
21
+ `;
22
+ export default function dbCommand(program) {
23
+ program
24
+ .command("db", "Run SQL against the database")
25
+ .help(dbHelpText)
26
+ .action(() => {
27
+ console.log(dbHelpText);
28
+ });
29
+ program
30
+ .command("db sql", "Execute a SQL string")
31
+ .hide()
32
+ .argument("<sql>", "SQL to execute")
33
+ .option("-f, --format <format>", "Result format for SELECT queries: table, json, jsonl, toon, or csv", {
34
+ default: "table",
35
+ validator: ["table", "json", "jsonl", "toon", "csv"],
36
+ })
37
+ .option("--verbose", "Execute each statement separately with progress labels", {
38
+ default: false,
39
+ })
40
+ .action(async ({ args, options, logger, }) => {
41
+ try {
42
+ const fmt = options.format;
43
+ const format = fmt === "json" || fmt === "jsonl" || fmt === "toon" || fmt === "csv" ? fmt : "table";
44
+ await dbSql(args.sql, {
45
+ verbose: options.verbose === true,
46
+ format,
47
+ quiet: options.silent === true || options.quiet === true,
48
+ }, logger);
49
+ }
50
+ catch (error) {
51
+ const message = error instanceof Error ? error.message : String(error);
52
+ logger.error(message);
53
+ process.exit(1);
54
+ }
55
+ });
56
+ program
57
+ .command("db run", "Execute a .sql file")
58
+ .hide()
59
+ .argument("<file>", "Path to .sql file")
60
+ .option("--verbose", "Log each SQL statement as it runs", { default: false })
61
+ .action(async ({ args, options, logger, }) => {
62
+ try {
63
+ await dbRun(args.file, { verbose: options.verbose === true }, logger);
64
+ }
65
+ catch (error) {
66
+ const message = error instanceof Error ? error.message : String(error);
67
+ logger.error(message);
68
+ process.exit(1);
69
+ }
70
+ });
71
+ program
72
+ .command("db dump", "Dump schema from a trailz env to SQL")
73
+ .hide()
74
+ .argument("<env>", "Environment name (blt env list)")
75
+ .option("-s, --schema <name>", "Postgres schema to dump", { default: "public" })
76
+ .option("--dir <path>", "Output directory for SQL artifacts", { default: "diff" })
77
+ .action(async ({ args, options, logger, }) => {
78
+ try {
79
+ await dbDump({
80
+ env: args.env,
81
+ schema: options.schema || "public",
82
+ dir: options.dir || "diff",
83
+ }, logger);
84
+ }
85
+ catch (error) {
86
+ const message = error instanceof Error ? error.message : String(error);
87
+ logger.error(message);
88
+ process.exit(1);
89
+ }
90
+ });
91
+ program
92
+ .command("db patch", "Write roll-forward patch SQL from source to target (does not apply)")
93
+ .hide()
94
+ .argument("<source-env>", "Source env name (blt env list) or path to .sql dump")
95
+ .argument("<target-env>", "Target env name (blt env list) or path to .sql dump")
96
+ .option("-s, --schema <schemas>", "Comma-separated Postgres schemas", { default: "public" })
97
+ .option("-n, --name <file>", "Patch SQL filename", { default: DEFAULT_PATCH_NAME })
98
+ .option("--dir <path>", "Output directory for the patch file", { default: "diff" })
99
+ .action(async ({ args, options, logger, }) => {
100
+ try {
101
+ await dbPatch({
102
+ sourceEnv: args.sourceEnv,
103
+ targetEnv: args.targetEnv,
104
+ schema: options.schema || "public",
105
+ name: options.name || DEFAULT_PATCH_NAME,
106
+ dir: options.dir || "diff",
107
+ }, logger);
108
+ }
109
+ catch (error) {
110
+ const message = error instanceof Error ? error.message : String(error);
111
+ logger.error(message);
112
+ process.exit(1);
113
+ }
114
+ });
115
+ }
116
+ //# sourceMappingURL=db.js.map