@rebasepro/server-postgres 0.21.0 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -13
- package/dist/{BranchService-W3DMfcZZ.js → BranchService-CucnFcSE.js} +2 -2
- package/dist/{BranchService-W3DMfcZZ.js.map → BranchService-CucnFcSE.js.map} +1 -1
- package/dist/PostgresBackendDriver.d.ts +26 -10
- package/dist/backup/backup-cron.d.ts +28 -1
- package/dist/{backup-cli-Bp-ou6o2.js → backup-cli-CkjsJEcu.js} +3 -2
- package/dist/backup-cli-CkjsJEcu.js.map +1 -0
- package/dist/{cli-errors-C3g_kHBw.js → cli-errors-Dka89exj.js} +19 -2
- package/dist/cli-errors-Dka89exj.js.map +1 -0
- package/dist/cli.js +15 -8
- package/dist/cli.js.map +1 -1
- package/dist/{doctor-ByFWL_ET.js → doctor-Gzzd8wTq.js} +4 -4
- package/dist/{doctor-ByFWL_ET.js.map → doctor-Gzzd8wTq.js.map} +1 -1
- package/dist/{ensure-collection-policies-CQGHln-y.js → ensure-collection-policies-B4IDFtQ-.js} +2 -2
- package/dist/{ensure-collection-policies-CQGHln-y.js.map → ensure-collection-policies-B4IDFtQ-.js.map} +1 -1
- package/dist/{ensure-collection-tables-Bkvehxdm.js → ensure-collection-tables-Cr2ye5JC.js} +2 -2
- package/dist/{ensure-collection-tables-Bkvehxdm.js.map → ensure-collection-tables-Cr2ye5JC.js.map} +1 -1
- package/dist/{generate-drizzle-schema-vSK-VdYT.js → generate-drizzle-schema-D2MDdJt-.js} +2 -2
- package/dist/{generate-drizzle-schema-vSK-VdYT.js.map → generate-drizzle-schema-D2MDdJt-.js.map} +1 -1
- package/dist/{generate-drizzle-schema-logic-Dfyf_MRu.js → generate-drizzle-schema-logic-DFa9qy9u.js} +4 -2
- package/dist/{generate-drizzle-schema-logic-Dfyf_MRu.js.map → generate-drizzle-schema-logic-DFa9qy9u.js.map} +1 -1
- package/dist/{generated-schema-staleness-DRQe2BpC.js → generated-schema-staleness-Di9c4ZxN.js} +9 -5
- package/dist/{generated-schema-staleness-DRQe2BpC.js.map → generated-schema-staleness-Di9c4ZxN.js.map} +1 -1
- package/dist/index.es.js +264 -180
- package/dist/index.es.js.map +1 -1
- package/dist/schema/doctor-cli.js +2 -2
- package/dist/schema/generate-drizzle-schema.js +1 -1
- package/dist/schema/generated-schema-staleness.d.ts +22 -0
- package/dist/services/realtimeService.d.ts +75 -12
- package/package.json +7 -7
- package/dist/backup-cli-Bp-ou6o2.js.map +0 -1
- package/dist/cli-errors-C3g_kHBw.js.map +0 -1
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["../src/schema/destructive-sql.ts","../src/schema/generated-column-conflicts.ts","../src/schema/carved-out-migration.ts","../src/schema/atlas-argv.ts","../src/branch-argv.ts","../src/cli-flags.ts","../src/cli-collections-path.ts","../src/backup-argv.ts","../src/branch-prune.ts","../src/cli.ts"],"sourcesContent":["/**\n * Pure helpers that classify an Atlas declarative-apply plan as destructive\n * or not, and decide what `rebase db push` should do about it.\n *\n * `db push` runs `atlas schema apply` to make the live database match the\n * generated `schema.sql`. Removing a collection field compiles to\n * `DROP COLUMN`; renaming compiles to drop-then-add — either destroys data.\n * We first run the apply with `--dry-run` to obtain the planned SQL, scan it\n * here, and refuse to auto-approve anything destructive without an explicit\n * opt-in.\n *\n * Everything in this file is side-effect free so it can be unit-tested\n * without Atlas or a database.\n */\n\n/**\n * SQL fragments that destroy data or data-bearing objects. Matched\n * case-insensitively against each statement of the plan. `IF EXISTS` /\n * whitespace variations are tolerated by the regexes below.\n */\nconst DESTRUCTIVE_PATTERNS: { label: string; re: RegExp }[] = [\n { label: \"DROP TABLE\", re: /\\bDROP\\s+TABLE\\b/i },\n { label: \"DROP COLUMN\", re: /\\bDROP\\s+COLUMN\\b/i },\n { label: \"DROP SCHEMA\", re: /\\bDROP\\s+SCHEMA\\b/i },\n { label: \"DROP VIEW\", re: /\\bDROP\\s+(MATERIALIZED\\s+)?VIEW\\b/i },\n { label: \"DROP TYPE\", re: /\\bDROP\\s+TYPE\\b/i },\n { label: \"TRUNCATE\", re: /\\bTRUNCATE\\b/i }\n];\n\n/**\n * Split a SQL script into individual statements, dropping blank lines and\n * `--` comment lines. Deliberately simple: Atlas emits one plain statement\n * per `;`, without string literals that contain semicolons in a schema DDL\n * plan, so a naive split is safe and keeps this dependency-free.\n */\nexport function splitSqlStatements(sql: string): string[] {\n // Strip full-line SQL comments so a commented-out DROP never trips the\n // detector, then split on semicolons.\n const withoutComments = sql\n .split(\"\\n\")\n .filter((line) => !line.trim().startsWith(\"--\"))\n .join(\"\\n\");\n return withoutComments\n .split(\";\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n}\n\nexport interface DestructiveStatement {\n /** The offending statement (trimmed, without the trailing `;`). */\n statement: string;\n /** Which destructive operation it was flagged for, e.g. \"DROP COLUMN\". */\n kind: string;\n}\n\n/**\n * Scan an Atlas plan (the SQL printed by `schema apply --dry-run`) and return\n * the statements that would destroy data. An empty array means the plan is\n * safe to auto-approve.\n */\nexport function detectDestructiveStatements(planSql: string): DestructiveStatement[] {\n const found: DestructiveStatement[] = [];\n for (const statement of splitSqlStatements(planSql)) {\n for (const { label, re } of DESTRUCTIVE_PATTERNS) {\n if (re.test(statement)) {\n found.push({ statement, kind: label });\n break; // one label per statement is enough to flag it\n }\n }\n }\n return found;\n}\n\nexport type PushDecision = \"apply\" | \"confirm\" | \"refuse\";\n\n/**\n * Decide how `db push` should proceed given the plan's destructiveness and\n * the invocation context.\n *\n * - No destructive statements → `apply` (safe to auto-approve).\n * - Destructive + `--allow-destructive` → `apply` (operator opted in).\n * - Destructive + interactive TTY → `confirm` (prompt before applying).\n * - Destructive + non-interactive → `refuse` (never silently drop data in\n * CI / scripts / agents).\n */\nexport function decidePushSafety(opts: {\n destructiveCount: number;\n allowDestructive: boolean;\n interactive: boolean;\n}): PushDecision {\n if (opts.destructiveCount === 0) return \"apply\";\n if (opts.allowDestructive) return \"apply\";\n return opts.interactive ? \"confirm\" : \"refuse\";\n}\n","/**\n * Which columns an Atlas plan cannot touch, because a generated column reads\n * them.\n *\n * PostgreSQL refuses `ALTER COLUMN … TYPE` and `DROP COLUMN` on any column a\n * `GENERATED ALWAYS AS … STORED` expression depends on:\n *\n * cannot alter type of a column used by a generated column\n *\n * Atlas cannot see that coming. A search block's `tsvector` is *deliberately*\n * hidden from it (`searchExcludePatterns`) — Rebase owns that column, and an\n * Atlas that could see it would plan a `DROP COLUMN` for it on every push,\n * since the desired state it is given never mentions one. So Atlas plans an\n * alter against a column whose dependant is invisible to it, PostgreSQL\n * refuses, and because `schema apply` runs its plan in a single transaction\n * **every unrelated statement rolls back with it**. One `varchar(255)` → `text`\n * widening on a searched column is enough to make `rebase db push` a no-op\n * forever, with an error that names neither the generated column nor the reason.\n *\n * The fix is the same one the search column's own stamp guard already\n * prescribes when a `search` block changes: drop the generated column, let the\n * apply through, and rebuild it from `search.sql` afterwards. It is cheap to\n * rebuild (one table rewrite, which the `ALTER … TYPE` was going to cost\n * anyway) and there is no other order that works — the expression cannot be\n * altered in place at all.\n *\n * Everything here is side-effect free: the plan is text and the dependencies\n * are rows someone else read. Unit-tested in\n * `generated-column-conflicts.test.ts`.\n */\nimport { splitSqlStatements } from \"./destructive-sql\";\n\n/** An operation on a column that PostgreSQL refuses while a dependant exists. */\nexport type ColumnMutationKind = \"type\" | \"drop\";\n\nexport interface ColumnMutation {\n /** Absent when the plan did not qualify the table; matched loosely then. */\n schema?: string;\n table: string;\n column: string;\n kind: ColumnMutationKind;\n}\n\n/** One `generated column → column it reads` edge, as read from the catalogue. */\nexport interface GeneratedColumnDependency {\n schema: string;\n table: string;\n /** The generated column. */\n column: string;\n /** A column its expression reads. */\n dependsOn: string;\n}\n\n/** A generated column standing in the way of the plan, and why. */\nexport interface GeneratedColumnConflict {\n schema: string;\n table: string;\n /** The generated column that has to go before the apply. */\n column: string;\n /** The mutated columns it reads, deduplicated and sorted. */\n blocking: { column: string; kind: ColumnMutationKind }[];\n}\n\n/** `\"public\".\"posts\"` / `public.posts` / `posts` → its parts. */\nconst IDENT = String.raw`(?:\"[^\"]+\"|[A-Za-z_][A-Za-z0-9_$]*)`;\nconst TABLE_RE = new RegExp(String.raw`^ALTER\\s+TABLE\\s+(?:ONLY\\s+)?(${IDENT})(?:\\.(${IDENT}))?`, \"i\");\nconst ALTER_COLUMN_RE = new RegExp(\n String.raw`\\bALTER\\s+(?:COLUMN\\s+)?(${IDENT})\\s+(?:SET\\s+DATA\\s+)?TYPE\\b`, \"gi\"\n);\nconst DROP_COLUMN_RE = new RegExp(\n String.raw`\\bDROP\\s+COLUMN\\s+(?:IF\\s+EXISTS\\s+)?(${IDENT})`, \"gi\"\n);\n\nconst unquote = (ident: string): string =>\n ident.startsWith(\"\\\"\") ? ident.slice(1, -1) : ident;\n\n/**\n * Strip Atlas's plan rendering from a statement.\n *\n * What `schema apply --dry-run` prints is not a SQL file: each statement is\n * indented under a `-- modify \"posts\" table` heading and prefixed with `-> `,\n * with an `-- ok (12µs)` line after it. `splitSqlStatements` drops the comment\n * lines, and this drops the arrow — without it an anchored `^ALTER TABLE`\n * matches nothing at all, which is a silent no-op rather than an error.\n */\nconst stripPlanMarker = (statement: string): string =>\n statement.replace(/^\\s*->\\s*/, \"\").trim();\n\n/**\n * Every column an Atlas plan retypes or drops, with the table it belongs to.\n *\n * One statement carries many clauses — Atlas emits `ALTER TABLE \"public\".\"posts\"\n * ALTER COLUMN \"title\" TYPE text, ALTER COLUMN \"slug\" TYPE text, …` — so the\n * table is read once per statement and the clauses are scanned within it.\n */\nexport function parseColumnMutations(planSql: string): ColumnMutation[] {\n const mutations: ColumnMutation[] = [];\n\n for (const raw of splitSqlStatements(planSql)) {\n const statement = stripPlanMarker(raw);\n const table = TABLE_RE.exec(statement);\n if (!table) continue;\n // With both groups present the first is the schema; with one, the\n // statement named a bare table and the schema is whatever search_path\n // resolves to — which we cannot know here, so it stays undefined and\n // `findGeneratedColumnConflicts` matches on the table name alone.\n const [schema, name] = table[2]\n ? [unquote(table[1]), unquote(table[2])]\n : [undefined, unquote(table[1])];\n\n const collect = (re: RegExp, kind: ColumnMutationKind) => {\n re.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(statement)) !== null) {\n mutations.push({ schema, table: name, column: unquote(match[1]), kind });\n }\n };\n collect(ALTER_COLUMN_RE, \"type\");\n collect(DROP_COLUMN_RE, \"drop\");\n }\n\n return mutations;\n}\n\n/**\n * The generated columns that block a plan: those reading a column it retypes\n * or drops.\n *\n * A mutation with no schema matches on table name alone. That is deliberately\n * loose — a bare `ALTER TABLE posts` resolves through `search_path` at\n * execution time, and guessing wrong in the *permissive* direction costs a\n * generated column that is rebuilt seconds later, while guessing wrong in the\n * strict direction costs the whole push.\n */\nexport function findGeneratedColumnConflicts(\n mutations: ColumnMutation[],\n dependencies: GeneratedColumnDependency[]\n): GeneratedColumnConflict[] {\n const conflicts = new Map<string, GeneratedColumnConflict>();\n\n for (const dependency of dependencies) {\n for (const mutation of mutations) {\n if (mutation.table !== dependency.table) continue;\n if (mutation.schema !== undefined && mutation.schema !== dependency.schema) continue;\n if (mutation.column !== dependency.dependsOn) continue;\n\n const key = `${dependency.schema}.${dependency.table}.${dependency.column}`;\n const conflict = conflicts.get(key) ?? {\n schema: dependency.schema,\n table: dependency.table,\n column: dependency.column,\n blocking: []\n };\n if (!conflict.blocking.some(b => b.column === mutation.column && b.kind === mutation.kind)) {\n conflict.blocking.push({ column: mutation.column, kind: mutation.kind });\n }\n conflicts.set(key, conflict);\n }\n }\n\n const ordered = [...conflicts.values()];\n for (const conflict of ordered) conflict.blocking.sort((a, b) => a.column.localeCompare(b.column));\n return ordered.sort((a, b) => `${a.schema}.${a.table}.${a.column}`.localeCompare(`${b.schema}.${b.table}.${b.column}`));\n}\n\n/**\n * Split the conflicts into the ones Rebase can rebuild and the ones it cannot.\n *\n * `managed` is decided by the very list that hid the column from Atlas: a\n * `schema.table.column` exclude pattern means Rebase generated the column and\n * `search.sql` will put it back. Anything else is somebody's hand-written\n * generated column — dropping it would destroy a definition Rebase has no copy\n * of, so it is reported and the push stops instead.\n */\nexport function partitionByOwnership(\n conflicts: GeneratedColumnConflict[],\n excludePatterns: string[]\n): { managed: GeneratedColumnConflict[]; foreign: GeneratedColumnConflict[] } {\n const owned = new Set(excludePatterns);\n const managed: GeneratedColumnConflict[] = [];\n const foreign: GeneratedColumnConflict[] = [];\n for (const conflict of conflicts) {\n const target = `${conflict.schema}.${conflict.table}.${conflict.column}`;\n (owned.has(target) ? managed : foreign).push(conflict);\n }\n return { managed, foreign };\n}\n\n/**\n * `ALTER TABLE … DROP COLUMN …` for each conflict, in catalogue order.\n *\n * `ifExists` is for the migration path, where the statement is written now and\n * runs later against a database nobody can inspect: on a fresh one the column\n * does not exist yet (the migration is about to create the table), on a live\n * one it does, and the same file has to survive both.\n */\nexport function dropGeneratedColumnStatements(\n conflicts: GeneratedColumnConflict[],\n opts: { ifExists?: boolean } = {}\n): string[] {\n const guard = opts.ifExists ? \"IF EXISTS \" : \"\";\n return conflicts.map(c => `ALTER TABLE \"${c.schema}\".\"${c.table}\" DROP COLUMN ${guard}\"${c.column}\";`);\n}\n\n/**\n * The preamble a migration needs when it retypes a column a search block reads.\n *\n * Prepended, because the drop has to precede the `ALTER COLUMN … TYPE` that\n * PostgreSQL would otherwise refuse. The column comes back at the end of the\n * same migration: `db generate` appends `search.sql`, whose\n * `ADD COLUMN IF NOT EXISTS` rebuilds the column, its index and its stamp.\n */\nexport function migrationDropPreamble(conflicts: GeneratedColumnConflict[]): string {\n if (conflicts.length === 0) return \"\";\n const reasons = conflicts.map(c => {\n const reads = c.blocking.map(b => `${b.column} (${b.kind})`).join(\", \");\n return `-- ${describeConflict(c)} reads ${reads}`;\n });\n return [\n \"-- Rebase: generated columns removed so the statements below can run.\",\n \"-- PostgreSQL refuses to retype or drop a column while a GENERATED\",\n \"-- ALWAYS AS … STORED expression reads it.\",\n ...reasons,\n \"-- The search DDL appended at the end of this migration rebuilds them.\",\n ...dropGeneratedColumnStatements(conflicts, { ifExists: true }),\n \"\"\n ].join(\"\\n\");\n}\n\n/** `public.posts.search_vector`, the way every message here names one. */\nexport function describeConflict(conflict: GeneratedColumnConflict): string {\n return `${conflict.schema}.${conflict.table}.${conflict.column}`;\n}\n","/**\n * Keep the objects Rebase carved out of Atlas's view out of the migrations\n * Atlas writes.\n *\n * `db push` protects them with `--exclude`. `atlas migrate diff` has no such\n * flag — measured on the pinned 1.2.3, `--exclude` is rejected outright with\n * `unknown flag`, and the `exclude` attribute of an `atlas.hcl` `env` block is\n * accepted and then silently ignored on that path. So the diff sees the search\n * column that the migration directory's own appended DDL created when it\n * replayed, does not see it in `schema.sql`, and plans a drop:\n *\n * ALTER TABLE \"public\".\"talents\" DROP COLUMN \"search_vector\";\n *\n * That statement is removed here, after Atlas has written the file and before\n * anything is appended to it — so the input is always Atlas's own plain output,\n * never the dollar-quoted helper bodies that get appended afterwards.\n *\n * The drop does not arrive alone. Atlas folds every change to one table into a\n * single statement, so a real edit in the same run produces\n *\n * ALTER TABLE \"public\".\"talents\"\n * DROP COLUMN \"search_vector\", DROP COLUMN \"interests\", ADD COLUMN \"headline\" text NULL;\n *\n * and dropping the whole statement would silently throw away a migration the\n * project asked for. The removal is therefore per *clause*.\n *\n * Fail-safe throughout: a statement that mentions a carved-out object but does\n * not match a shape this understands is left exactly as it is and reported as\n * `unhandled`, so the caller can say so out loud. A spurious drop the developer\n * can see beats a migration quietly rewritten wrong.\n */\n\n/** Anything Postgres accepts in an unquoted identifier past ASCII. */\nconst IDENT = \"(?:\\\"(?:[^\\\"]|\\\"\\\")*\\\"|[A-Za-z_\\\\u0080-\\\\uffff][\\\\w$\\\\u0080-\\\\uffff]*)\";\nconst QUALIFIED = `${IDENT}(?:\\\\s*\\\\.\\\\s*${IDENT})*`;\n\nconst ALTER_TABLE_RE = new RegExp(`^ALTER\\\\s+TABLE\\\\s+(?:ONLY\\\\s+)?(${QUALIFIED})\\\\s+([\\\\s\\\\S]+)$`, \"i\");\nconst DROP_COLUMN_RE = new RegExp(`^DROP\\\\s+(?:COLUMN\\\\s+)?(?:IF\\\\s+EXISTS\\\\s+)?(${IDENT})$`, \"i\");\nconst DROP_INDEX_RE = new RegExp(`^DROP\\\\s+INDEX\\\\s+(?:CONCURRENTLY\\\\s+)?(?:IF\\\\s+EXISTS\\\\s+)?(${QUALIFIED})$`, \"i\");\n\n/**\n * Does this statement destroy anything at all?\n *\n * The gate on reporting. A statement that merely *names* a carved-out object —\n * `COMMENT ON COLUMN … \"search_vector\"` — is not a problem and must not be\n * reported as one, because an unrewritable drop stops the caller outright.\n */\nconst MENTIONS_DROP = /\\bDROP\\b/i;\n\n/** One `schema.table.object` exclude pattern, taken apart. */\nexport interface CarvedOutObject {\n schema: string;\n table: string;\n object: string;\n}\n\nexport interface StripResult {\n /** The migration text with the carved-out clauses gone. */\n sql: string;\n /** What was removed, as SQL fragments, for reporting. */\n removed: string[];\n /**\n * Statements naming a carved-out object that this could not rewrite with\n * confidence. Left untouched in `sql`.\n */\n unhandled: string[];\n /** True when nothing but comments and whitespace survives. */\n empty: boolean;\n}\n\n/**\n * Split `schema.table.object` patterns. Anything not in three parts is\n * ignored rather than guessed at — the two-part form is the one Atlas itself\n * silently mis-reads, and repeating that mistake here would be worse than\n * doing nothing.\n */\nexport function parseExcludePatterns(patterns: string[]): CarvedOutObject[] {\n const parsed: CarvedOutObject[] = [];\n for (const pattern of patterns) {\n const parts = pattern.split(\".\");\n if (parts.length !== 3) continue;\n if (parts.some((p) => p.length === 0)) continue;\n parsed.push({ schema: parts[0], table: parts[1], object: parts[2] });\n }\n return parsed;\n}\n\n/** `\"public\"` and `public` are the same name; `\"Public\"` is not `public`. */\nfunction unquoteIdentifier(raw: string): string {\n const trimmed = raw.trim();\n if (trimmed.startsWith(\"\\\"\") && trimmed.endsWith(\"\\\"\") && trimmed.length >= 2) {\n return trimmed.slice(1, -1).replace(/\"\"/g, \"\\\"\");\n }\n // An unquoted identifier is folded to lower case by Postgres.\n return trimmed.toLowerCase();\n}\n\n/** Split a dotted identifier at its top-level dots, respecting quoting. */\nfunction splitQualifiedName(raw: string): string[] | null {\n const parts: string[] = [];\n let current = \"\";\n let inQuote = false;\n for (let i = 0; i < raw.length; i++) {\n const ch = raw[i];\n if (inQuote) {\n if (ch === \"\\\"\") {\n if (raw[i + 1] === \"\\\"\") { current += \"\\\"\\\"\"; i++; continue; }\n inQuote = false;\n }\n current += ch;\n continue;\n }\n if (ch === \"\\\"\") { inQuote = true; current += ch; continue; }\n if (ch === \".\") { parts.push(current); current = \"\"; continue; }\n current += ch;\n }\n if (inQuote) return null;\n parts.push(current);\n return parts.map(unquoteIdentifier);\n}\n\n/**\n * One statement located in the source text, with the comment lines that\n * introduce it. Atlas writes `-- Modify \"talents\" table` above each statement;\n * removing the statement without its comment leaves a caption over nothing.\n */\ninterface LocatedStatement {\n /** Offset of the first character of the leading comment block. */\n start: number;\n /** Offset just past the terminating semicolon. */\n end: number;\n /** Offset of the first character of the statement itself. */\n bodyStart: number;\n /** The statement without its leading comments or trailing semicolon. */\n body: string;\n}\n\n/**\n * Walk the script and locate every statement. Quote-, comment- and\n * dollar-aware: the appended halves of a migration are not passed here, but a\n * splitter that shreds a `DO $tag$ ... $tag$` block is a trap worth not\n * leaving behind — it is how the derived-names renderer broke.\n *\n * Returns null if the text ends inside a quote or a dollar-quoted body, or\n * trails off in a statement with no semicolon. Either means this cannot be\n * reasoned about safely.\n */\nfunction locateStatements(sql: string): LocatedStatement[] | null {\n const statements: LocatedStatement[] = [];\n let i = 0;\n let statementStart = 0;\n let sawCode = false;\n\n const pushStatement = (endExclusive: number) => {\n const leading = sql.slice(statementStart, endExclusive);\n // The leading run of comment/blank lines belongs to this statement.\n let consumed = 0;\n for (const line of leading.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed === \"\" || trimmed.startsWith(\"--\")) {\n consumed += line.length + 1;\n continue;\n }\n break;\n }\n const bodyStart = statementStart + consumed;\n statements.push({\n start: statementStart,\n end: endExclusive,\n bodyStart,\n body: sql.slice(bodyStart, endExclusive).replace(/;\\s*$/, \"\").trim()\n });\n };\n\n while (i < sql.length) {\n const ch = sql[i];\n\n if (ch === \"-\" && sql[i + 1] === \"-\") {\n const nl = sql.indexOf(\"\\n\", i);\n i = nl === -1 ? sql.length : nl + 1;\n continue;\n }\n if (ch === \"/\" && sql[i + 1] === \"*\") {\n const close = sql.indexOf(\"*/\", i + 2);\n if (close === -1) return null;\n i = close + 2;\n sawCode = true;\n continue;\n }\n if (ch === \"'\" || ch === \"\\\"\") {\n const quote = ch;\n i++;\n let closed = false;\n while (i < sql.length) {\n if (sql[i] === quote) {\n if (sql[i + 1] === quote) { i += 2; continue; }\n i++;\n closed = true;\n break;\n }\n i++;\n }\n if (!closed) return null;\n sawCode = true;\n continue;\n }\n if (ch === \"$\") {\n const tag = /^\\$(?:[A-Za-z_\\u0080-\\uffff][\\w\\u0080-\\uffff]*)?\\$/.exec(sql.slice(i));\n if (tag) {\n const close = sql.indexOf(tag[0], i + tag[0].length);\n if (close === -1) return null;\n i = close + tag[0].length;\n sawCode = true;\n continue;\n }\n }\n if (ch === \";\") {\n pushStatement(i + 1);\n i++;\n statementStart = i;\n sawCode = false;\n continue;\n }\n if (!/\\s/.test(ch)) sawCode = true;\n i++;\n }\n\n // Trailing text with no semicolon: only comments and whitespace is fine.\n if (sawCode) return null;\n return statements;\n}\n\n/** Split an ALTER TABLE action list at its top-level commas. */\nfunction splitClauses(actions: string): string[] | null {\n const clauses: string[] = [];\n let depth = 0;\n let current = \"\";\n let i = 0;\n while (i < actions.length) {\n const ch = actions[i];\n if (ch === \"'\" || ch === \"\\\"\") {\n const quote = ch;\n current += ch;\n i++;\n let closed = false;\n while (i < actions.length) {\n current += actions[i];\n if (actions[i] === quote) {\n if (actions[i + 1] === quote) { current += actions[i + 1]; i += 2; continue; }\n i++;\n closed = true;\n break;\n }\n i++;\n }\n if (!closed) return null;\n continue;\n }\n if (ch === \"(\") { depth++; current += ch; i++; continue; }\n if (ch === \")\") { depth--; current += ch; i++; continue; }\n if (ch === \",\" && depth === 0) { clauses.push(current); current = \"\"; i++; continue; }\n current += ch;\n i++;\n }\n if (depth !== 0) return null;\n clauses.push(current);\n return clauses.map((c) => c.trim()).filter((c) => c.length > 0);\n}\n\n/**\n * Remove every clause and statement that would drop one of `patterns`.\n *\n * `patterns` are the `schema.table.object` strings the CLI already builds for\n * Atlas's `--exclude`, so the diff path and the apply path protect exactly the\n * same set by construction.\n */\nexport function stripCarvedOutStatements(migrationSql: string, patterns: string[]): StripResult {\n const carved = parseExcludePatterns(patterns);\n if (carved.length === 0) {\n return { sql: migrationSql, removed: [], unhandled: [], empty: isBlank(migrationSql) };\n }\n\n const located = locateStatements(migrationSql);\n if (located === null) {\n // Nothing can be trusted about the offsets, so nothing moves. Worth\n // stopping the caller over only if one of ours is being dropped in\n // there; otherwise this file has nothing to do with us.\n const atStake = MENTIONS_DROP.test(migrationSql)\n && carved.some((c) => migrationSql.includes(c.object));\n return {\n sql: migrationSql,\n removed: [],\n unhandled: atStake ? [migrationSql.trim()] : [],\n empty: isBlank(migrationSql)\n };\n }\n\n const removed: string[] = [];\n const unhandled: string[] = [];\n // Edits as [start, end) → replacement, applied back-to-front so the\n // offsets of the ones still pending stay valid.\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n for (const statement of located) {\n if (!carved.some((c) => statement.body.includes(c.object))) continue;\n\n const dropIndex = DROP_INDEX_RE.exec(statement.body);\n if (dropIndex) {\n const parts = splitQualifiedName(dropIndex[1]);\n const name = parts?.[parts.length - 1];\n const schema = parts && parts.length > 1 ? parts[parts.length - 2] : undefined;\n if (name !== undefined && carved.some((c) =>\n c.object === name && (schema === undefined || c.schema === schema))) {\n removed.push(statement.body);\n edits.push({ start: statement.start, end: statement.end, replacement: \"\" });\n } else {\n // A near-miss on the name — some other index whose name\n // contains ours. Left alone, and still a drop, so still\n // reported.\n unhandled.push(statement.body);\n }\n continue;\n }\n\n // Anything else naming a carved-out object is only our business if it\n // destroys something. `COMMENT ON COLUMN … \"search_vector\"` does not.\n const alter = ALTER_TABLE_RE.exec(statement.body);\n if (!alter) {\n if (MENTIONS_DROP.test(statement.body)) unhandled.push(statement.body);\n continue;\n }\n\n const target = splitQualifiedName(alter[1]);\n if (!target) {\n if (MENTIONS_DROP.test(statement.body)) unhandled.push(statement.body);\n continue;\n }\n const table = target[target.length - 1];\n const schema = target.length > 1 ? target[target.length - 2] : undefined;\n\n const clauses = splitClauses(alter[2]);\n if (!clauses) {\n if (MENTIONS_DROP.test(statement.body)) unhandled.push(statement.body);\n continue;\n }\n\n const survivors: string[] = [];\n let removedHere = 0;\n let unhandledHere = false;\n for (const clause of clauses) {\n const drop = DROP_COLUMN_RE.exec(clause);\n const column = drop ? unquoteIdentifier(drop[1]) : undefined;\n const isCarved = column !== undefined && carved.some((c) =>\n c.object === column &&\n c.table === table &&\n (schema === undefined || c.schema === schema));\n if (isCarved) {\n removed.push(`ALTER TABLE ${alter[1]}: ${clause}`);\n removedHere++;\n continue;\n }\n // A clause naming a carved-out object in some other shape is not\n // something to guess at — if it destroys it.\n if (MENTIONS_DROP.test(clause) && carved.some((c) => clause.includes(c.object))) {\n unhandledHere = true;\n }\n survivors.push(clause);\n }\n\n if (unhandledHere) unhandled.push(statement.body);\n if (removedHere === 0) continue;\n\n if (survivors.length === 0) {\n edits.push({ start: statement.start, end: statement.end, replacement: \"\" });\n } else {\n edits.push({\n start: statement.bodyStart,\n end: statement.end,\n replacement: `ALTER TABLE ${alter[1]} ${survivors.join(\", \")};`\n });\n }\n }\n\n let sql = migrationSql;\n for (const edit of edits.sort((a, b) => b.start - a.start)) {\n sql = sql.slice(0, edit.start) + edit.replacement + sql.slice(edit.end);\n }\n if (edits.length > 0) sql = tidy(sql);\n\n return { sql, removed, unhandled, empty: isBlank(sql) };\n}\n\n/** Only comments and whitespace left — nothing a migration would do. */\nfunction isBlank(sql: string): boolean {\n return sql\n .split(\"\\n\")\n .every((line) => line.trim() === \"\" || line.trim().startsWith(\"--\"));\n}\n\n/** Collapse the blank runs an excision leaves behind. */\nfunction tidy(sql: string): string {\n const trimmed = sql.replace(/\\n{3,}/g, \"\\n\\n\").replace(/^\\s*\\n/, \"\").trimEnd();\n return trimmed.length === 0 ? \"\" : `${trimmed}\\n`;\n}\n","/**\n * The argv `runAtlas` hands the Atlas binary, as a pure function.\n *\n * Split out of `cli.ts` because the flags an Atlas subcommand accepts are not\n * uniform and getting one wrong is fatal rather than degraded: Atlas rejects an\n * unknown flag before doing any work, so a flag on the wrong subcommand takes\n * the whole command down.\n *\n * `--exclude` is the one that bit. Of the six invocations here, exactly one\n * accepts it. The guard this replaces was `args.includes(\"apply\") ||\n * args.includes(\"diff\")`, and reading it as a *subcommand* test is the trap:\n * `migrate apply` passes `args.includes(\"apply\")` just as `schema apply` does.\n * So the flag went onto three invocations, two of which reject it, and both\n * `rebase db generate` and `rebase db migrate` exited 1 with `unknown flag:\n * --exclude` for every project declaring a `search` block.\n *\n * The domain is half the identity of an Atlas subcommand, and a guard that\n * looks only at `args` cannot tell `schema apply` from `migrate apply`.\n *\n * Nothing here touches a database or the filesystem, so the whole matrix is\n * unit-tested in `atlas-argv.test.ts`.\n */\n\nexport interface AtlasInvocation {\n /** `schema` or `migrate`. */\n domain: string;\n /** The subcommand and its own flags, e.g. `[\"diff\", \"--dir\", \"file://…\"]`. */\n args: string[];\n /** The target database, already rewritten for libpq. */\n url: string;\n /** The database Atlas plans against, already rewritten for libpq. */\n devUrl: string;\n /**\n * Everything the caller resolved for `--exclude`, in the order it should\n * appear. Dropped entirely when the subcommand does not accept the flag —\n * see {@link acceptsExcludeFlag}.\n */\n excludes?: string[];\n}\n\n/**\n * Does this Atlas invocation accept `--exclude`?\n *\n * Only `atlas schema apply` does, on the pinned 1.2.3. Measured against the\n * binary: `migrate diff` and `migrate apply` both answer `unknown flag:\n * --exclude`, and neither lists it in `--help` (`migrate apply` offers\n * `--url/--dir/--format/--revisions-schema/--dry-run/--lock-name/--lock-timeout/`\n * `--skip-lock/--baseline/--to-version/--tx-mode/--exec-order/--allow-dirty`).\n * Hence `domain === \"schema\"` and not just the subcommand.\n *\n * The `exclude` attribute of an `atlas.hcl` `env` block is not a way round it\n * either: measured, it is accepted and then ignored on the diff path, which is\n * the silent-no-match shape that costs the most time to notice.\n *\n * So the diff keeps the carved-out objects out of the migration afterwards\n * instead, with `stripCarvedOutStatements`.\n */\nexport function acceptsExcludeFlag(domain: string, args: string[]): boolean {\n return domain === \"schema\" && args.includes(\"apply\");\n}\n\n/** Assemble the full argv, connection flags and all. */\nexport function buildAtlasArgs(invocation: AtlasInvocation): string[] {\n const { domain, args, url, devUrl, excludes = [] } = invocation;\n const argv = [domain, ...args];\n\n if (domain === \"schema\") {\n if (args.includes(\"apply\")) {\n argv.push(\"--url\", url, \"--dev-url\", devUrl);\n } else if (args.includes(\"clean\") || args.includes(\"inspect\")) {\n argv.push(\"--url\", url);\n }\n } else if (domain === \"migrate\") {\n if (args.includes(\"diff\")) {\n argv.push(\"--dev-url\", devUrl);\n } else if (args.includes(\"apply\") || args.includes(\"status\")) {\n argv.push(\"--url\", url, \"--revisions-schema\", \"rebase\");\n // Measured against the pinned binary: `sql/migrate: baseline and\n // allow-dirty are mutually exclusive`. `--baseline` is the caller's\n // explicit answer to the same question `--allow-dirty` answers by\n // default, so it wins, and adding both would refuse the command.\n if (args.includes(\"apply\") && !args.includes(\"--baseline\")) {\n argv.push(\"--allow-dirty\");\n }\n }\n }\n\n // Second line of defence, deliberately not a caller's responsibility: a\n // future caller that resolves excludes for the diff path gets them dropped\n // here rather than a command that will not run.\n if (acceptsExcludeFlag(domain, args)) {\n for (const exclude of excludes) {\n argv.push(\"--exclude\", exclude);\n }\n }\n\n return argv;\n}\n","/**\n * Argument shapes for `rebase db branch`, with no dependencies.\n *\n * Its own module for the same reason `schema/atlas-argv.ts` is: `cli.ts` pulls\n * in chalk, execa and the driver runtime, so a unit test that imports it cannot\n * run. Argv parsing is the part most worth testing and the part least in need\n * of any of that.\n */\n\n/**\n * Words on a `db branch` command line that no argument accounts for.\n *\n * `rebase db branch create alpha beta` created a branch called `alpha` and\n * threw `beta` away without a word. The shapes that produces are all quiet and\n * all wrong: an unquoted name (`create my feature` → `my`), a flag written\n * without its dashes (`create feat from main` → `feat`), a shell that split\n * something you thought was one token. In each case the command succeeds and\n * the branch is not the one asked for — and branch names are the thing you\n * later type to switch, delete, or point a deploy at.\n *\n * Anything starting with `-` is left alone rather than validated. This runs on\n * every branch subcommand, including ones added later with flags this function\n * has never heard of, and rejecting an unrecognised flag here would break them\n * from a distance. The value after a flag that takes one is skipped for the\n * same reason: it is that flag's argument, not a stray word.\n *\n * @param words The command's own arguments: action, name, then the rest.\n */\nexport function unexpectedBranchArgs(words: readonly string[]): string[] {\n const extras: string[] = [];\n\n // 0 is the action (\"create\"); the first bare word after it is the name.\n //\n // Found by scanning rather than by position, which is the fix: `[\"list\",\n // \"--database-url\", \"postgres://…\"]` put a flag in slot 1, so the scan\n // started past it and read the URL as a stray word.\n let seenName = false;\n for (let index = 1; index < words.length; index += 1) {\n const word = words[index];\n if (word.startsWith(\"-\")) {\n if (TAKES_A_VALUE.has(word.split(\"=\")[0])) index += 1;\n continue;\n }\n if (!seenName) {\n seenName = true;\n continue;\n }\n extras.push(word);\n }\n\n return extras;\n}\n\n/**\n * Branch-line flags whose next word belongs to them.\n *\n * `--from` was the only one listed, and `--database-url` is the one that bit:\n * `rebase db branch list --database-url postgres://…` — which the CLI itself\n * appends when the checkout is on a branch, so `rebase.branches` is read in the\n * parent where it lives — answered `✗ Unexpected argument: postgres://…`. The\n * `=` form carries its value in the same word and needs no skip.\n */\nconst TAKES_A_VALUE = new Set([\"--from\", \"--older-than\", \"--database-url\"]);\n","/**\n * The flags each driver command takes, in one place, and the check that\n * enforces them.\n *\n * Every parser in `cli.ts` runs `arg(..., { permissive: true })`, which does not\n * mean \"be lenient\" — it means **an undeclared flag becomes a positional**. So\n * `rebase db push --alow-destructive` did not fail: the typo landed in `_`, the\n * push ran with the destructive gate still closed, and the developer read the\n * refusal as Rebase ignoring the flag they had just typed. `rebase schema\n * generate --ouput src/schema.ts` was worse — it wrote the default path and\n * said nothing, so the next build compiled a file nobody had regenerated.\n *\n * The check has to live at the entry point rather than in those parsers, and\n * that is not a detail: `db push` and `db generate` re-enter `schemaCommand`\n * and `generatePostgresDdlCommand` with the *db* line, so a strict parser\n * inside either of them would reject `--allow-destructive` on a line where it\n * is correct. One validation, once, against the spec for the command the user\n * actually named; the inner parsers keep reading an already-validated line.\n *\n * Commands with their own argument handling — `db branch` (`unexpectedBranchArgs`),\n * `db backup`, `db restore`, `db backups` — are deliberately absent: they own\n * their spec, and a second list here would be one more thing to keep in step.\n * An absent entry is \"not checked here\", never \"takes nothing\".\n */\nimport arg from \"arg\";\n\n/**\n * Flags that reach this process on a line it did not compose.\n *\n * `rebase db …` hands the driver the user's whole line: the CLI *reads*\n * `--database-url` and `--docker` to resolve the database and then relays them\n * verbatim, and `--debug` is what `bin/rebase.js` prints after every failure as\n * the thing to re-run with. Rejecting any of the three would make the driver\n * refuse commands the CLI documents.\n */\nconst RELAYED_FLAGS: arg.Spec = {\n \"--database-url\": String,\n \"--docker\": Boolean,\n \"--debug\": Boolean,\n \"--help\": Boolean,\n \"-h\": \"--help\"\n};\n\n/** Keyed by `\"<domain> <subcommand>\"`, the way the user types it. */\nexport const DRIVER_FLAG_SPECS: Record<string, arg.Spec> = {\n \"db push\": {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--dry-run\": Boolean,\n \"--allow-destructive\": Boolean,\n \"--yes\": Boolean,\n \"-y\": \"--yes\"\n },\n \"db generate\": {\n \"--collections\": String,\n \"-c\": \"--collections\"\n },\n // Bare positionals still pass through to `atlas migrate apply`, which takes\n // an optional amount; flags do not, apart from `--baseline`.\n //\n // `--baseline <version>` is the escape hatch for the normal case, not an\n // exotic one: every Rebase boot ensures the schema, so a production\n // database has the tables before its first migration ever runs, and\n // `migrate apply` then dies on `type \"…\" already exists (42710)`. It maps\n // onto Atlas's own `migrate apply --baseline`, which writes the revision\n // row Atlas reads — no ledger of ours.\n \"db migrate\": {\n \"--baseline\": String\n },\n \"schema generate\": {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--output\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"--watch\": Boolean,\n \"-w\": \"--watch\"\n },\n \"schema introspect\": {\n \"--output\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--force\": Boolean,\n \"-f\": \"--force\",\n \"--schema\": String\n },\n \"schema stale\": {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--output\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"--fix\": Boolean\n }\n};\n\n/**\n * One destination flag, two spellings, everywhere.\n *\n * `--out` is the primary on `rebase build`, an alias on `generate-sdk`, `db\n * backup` and `cloud env pull`, and was refused outright by the three `schema`\n * commands — so the spelling a user learned on one command was an\n * \"unknown or unexpected option\" on the next. Neither name can be retired (both\n * are shipped), so both are accepted, and {@link assertOutputAliasesPaired}\n * makes that the rule rather than a habit.\n */\nexport const OUTPUT_FLAG_ALIASES = [\"--out\", \"--output\"] as const;\n\n/**\n * Every spec that names one of the pair names both.\n *\n * Exported so the CLI's own specs can be held to it too: the drift this fixes\n * ran across two packages, and a check that only reads this file would let the\n * next `--out`-only command through.\n */\nexport function assertOutputAliasesPaired(specs: Record<string, arg.Spec>): string[] {\n const problems: string[] = [];\n for (const [command, spec] of Object.entries(specs)) {\n const present = OUTPUT_FLAG_ALIASES.filter(flag => flag in spec);\n if (present.length === 0 || present.length === OUTPUT_FLAG_ALIASES.length) continue;\n const missing = OUTPUT_FLAG_ALIASES.filter(flag => !(flag in spec));\n problems.push(`\\`${command}\\` takes ${present.join(\", \")} but not ${missing.join(\", \")}`);\n }\n return problems;\n}\n\n/**\n * The `--collections` path the user typed, or `null` if they typed none.\n *\n * Read once, at the entry point, because every command that takes it re-enters\n * the generators with the same line and each of them resolved it again — which\n * is how \"Collections path not found\" came to be printed four times before the\n * real output, and how a path that does not exist got as far as *writing* an\n * empty schema.\n *\n * Permissive, and it has to be: {@link assertKnownFlags} has already judged the\n * line, and `db push` carries flags the `--collections` spec does not name.\n */\nexport function collectionsPathIn(args: string[]): string | null {\n try {\n const parsed = arg(\n { \"--collections\": String, \"-c\": \"--collections\" },\n { argv: args.slice(2), permissive: true }\n );\n\n return parsed[\"--collections\"] ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * The long flags a `--help` usage line documents.\n *\n * `\"rebase db push [--collections <dir>] [--dry-run] …\"` → `[\"--collections\",\n * \"--dry-run\"]`. Placeholders (`<dir>`) and the alternation inside a positional\n * (`<create|list|switch>`) are not flags and are not returned.\n */\nexport function flagsInUsage(usage: string): string[] {\n return [...new Set(usage.match(/--[a-z][a-z0-9-]*/g) ?? [])];\n}\n\n/**\n * Every flag the help documents is accepted, and every flag accepted is documented.\n *\n * The drift this catches shipped: `rebase db push --help` has printed\n * `[--dry-run]` since the flag was written, `DRIVER_FLAG_SPECS[\"db push\"]` never\n * listed it, and {@link assertKnownFlags} — added later to stop typos being\n * swallowed — turned the documented flag into `unknown or unexpected option`.\n * The only way to see a push's SQL was to trip the destructive gate, which is\n * the exact problem `--dry-run` was written to solve. Worse in a project on an\n * older driver, whose permissive parser *applied* the schema on that line.\n *\n * Two hand-maintained lists in two packages cannot be kept in step by care, so\n * they are held to each other instead: `usages` is keyed the way\n * {@link DRIVER_FLAG_SPECS} is (`\"db push\"`), and comes from the CLI's own help\n * pages. A key in only one of the two is not this function's business — the\n * help covers commands that parse their own lines (`db branch`, `db backup`),\n * and an absent spec entry means \"not checked here\".\n *\n * Aliases (`\"-c\": \"--collections\"`, `\"--out\": \"--output\"`) need no line of their\n * own: they are spellings of a documented flag. Neither do {@link RELAYED_FLAGS},\n * which every driver command accepts because the CLI relays them.\n */\nexport function assertSpecMatchesUsage(\n specs: Record<string, arg.Spec>,\n usages: Record<string, string>\n): string[] {\n const problems: string[] = [];\n for (const [command, spec] of Object.entries(specs)) {\n const usage = usages[command];\n if (usage === undefined) continue;\n\n const documented = flagsInUsage(usage);\n const accepted = Object.entries(spec);\n // An alias resolves to the flag it spells; only the target needs a line.\n const canonical = new Set(\n accepted\n .map(([flag, kind]) => (typeof kind === \"string\" ? kind : flag))\n .filter(flag => flag.startsWith(\"--\"))\n );\n\n for (const flag of documented) {\n if (flag in spec || flag in RELAYED_FLAGS) continue;\n problems.push(`\\`${command}\\` documents ${flag} in its usage line but the spec rejects it`);\n }\n for (const flag of canonical) {\n if (documented.includes(flag) || flag in RELAYED_FLAGS) continue;\n problems.push(`\\`${command}\\` accepts ${flag} but no usage line documents it`);\n }\n }\n return problems;\n}\n\n/**\n * Reject a flag the named command does not take.\n *\n * `args` is the driver's whole line — `[\"db\", \"push\", …]` — so the flags are\n * read from `args.slice(2)`, past the two command words.\n *\n * Throws rather than exiting: `runPluginCommand`'s caller already turns a\n * thrown error into one red line and exit 1, and a thrown error is what the\n * tests can see.\n */\nexport function assertKnownFlags(domain: string, subcommand: string | undefined, args: string[]): void {\n if (!subcommand) return;\n const spec = DRIVER_FLAG_SPECS[`${domain} ${subcommand}`];\n if (!spec) return;\n\n try {\n arg({ ...RELAYED_FLAGS, ...spec }, { argv: args.slice(2) });\n } catch (err) {\n if (err instanceof Error && (err as arg.ArgError).code === \"ARG_UNKNOWN_OPTION\") {\n throw new Error(\n `${err.message} — run \\`rebase ${domain} --help\\` for the options ` +\n `\\`${domain} ${subcommand}\\` takes.`\n );\n }\n throw err;\n }\n}\n","/**\n * `--collections <dir>`, checked once, before anything is written.\n *\n * A path that does not resolve used to warn and carry on. Four times over —\n * `schemaCommand`, `generatePostgresDdlCommand` and the Atlas argv assembly\n * each re-enter the loader with the same line — and then both generators wrote\n * an *empty* schema: `drizzle/schema.sql` truncated to `CREATE SCHEMA IF NOT\n * EXISTS \"rebase\";`, `src/schema.generated.ts` to ten lines. Both are committed\n * artifacts. The push that followed planned a `DROP TABLE` for every table in\n * the database, and the only thing between a typo and that was the destructive\n * gate.\n *\n * The check has to be here rather than inside `loadCollectionsForCli`, which is\n * deliberately forgiving: its callers use it to narrow what Atlas may touch,\n * and making a broken *file* fatal there would block a push over something\n * unrelated. \"Does the directory the user named exist\" is a different question,\n * it was answerable before the first write, and the code already knew.\n */\nimport fs from \"fs\";\nimport path from \"path\";\nimport chalk from \"chalk\";\nimport { outError } from \"./cli-output\";\n\n/**\n * Thrown rather than exited, so the tests can see it and the entry point owns\n * the exit code.\n *\n * `alreadyReported` is read by `reportCommandFailure`: the full diagnosis is on\n * stderr by the time this is thrown, and the point of the whole change is that\n * it is printed once.\n */\nexport class CollectionsPathMissing extends Error {\n readonly alreadyReported = true;\n\n constructor(readonly typed: string, readonly resolved: string) {\n super(`Collections path not found: \"${typed}\"`);\n this.name = \"CollectionsPathMissing\";\n }\n}\n\n/**\n * The whole message, in one place, because it is printed by two callers.\n *\n * Names what was typed, what it resolved to, and the working directory it\n * resolved against — a relative `--collections` is resolved against the cwd,\n * and the generated npm script runs with `cwd: backend/`, so \"the path is\n * right and the directory is wrong\" is the commonest way to arrive here.\n */\nexport function describeMissingCollectionsPath(typed: string, resolved: string): string {\n return [\n chalk.red(`✗ Collections path not found: \"${typed}\"`),\n chalk.gray(` Resolved to: ${resolved}`),\n chalk.gray(` (relative to cwd: ${process.cwd()})`),\n \"\",\n chalk.gray(\" Nothing was generated and nothing was applied — a schema generated from a\"),\n chalk.gray(\" directory that is not there is an empty one, and applying it would drop\"),\n chalk.gray(\" every table it does not describe.\"),\n \"\",\n chalk.gray(\" Pass an absolute path, or one relative to where you run the command.\")\n ].join(\"\\n\");\n}\n\n/**\n * Refuse a `--collections` path that does not exist.\n *\n * `null` means the flag was not given: the default (`../config/collections`) is\n * left to the loader, which warns and continues — a project may legitimately\n * have no collections directory, and a headless scaffold does.\n */\nexport function assertCollectionsPathExists(typed: string | null): void {\n if (typed === null) return;\n\n const resolved = path.resolve(process.cwd(), typed);\n if (fs.existsSync(resolved)) return;\n\n outError(\"\");\n outError(describeMissingCollectionsPath(typed, resolved));\n outError(\"\");\n throw new CollectionsPathMissing(typed, resolved);\n}\n","/**\n * Which of the two things `rebase db backup …` means.\n *\n * The cloud family spells the listing `rebase cloud db backup list`. Locally\n * the same words *created a backup*: `backup` dispatched straight to\n * `backupCommand`, which parsed permissively and dropped \"list\" into the\n * positionals it never reads. One CLI, two spellings, and the wrong guess wrote\n * a dump instead of reading one — quiet, slow, and on a large database not\n * free.\n *\n * A separate module for the same reason `branch-argv.ts` is one: the decision\n * is pure, and the dispatch it lives in cannot be imported without loading the\n * environment and reaching for a database.\n */\nexport type BackupAction = \"create\" | \"list\";\n\n/**\n * @param rawArgs the driver's whole line, `[\"db\", \"backup\", …]`.\n */\nexport function backupActionOf(rawArgs: readonly string[]): BackupAction {\n return rawArgs[2] === \"list\" ? \"list\" : \"create\";\n}\n","/**\n * What `rebase db branch prune` should remove, decided without a database.\n *\n * Branching had no cleanup story at all: no TTL, no prune, no `delete --all`,\n * and every branch is a **full-size copy** — `CREATE DATABASE ... TEMPLATE`\n * duplicates the files on disk, so five branches of a 100 GB database cost\n * 500 GB. The only way to reclaim any of it was to remember every name you had\n * ever typed.\n *\n * Three things drift apart, and they are not the same problem:\n *\n * 1. **Stale rows** — `rebase.branches` says a branch exists and its database\n * is gone. Someone dropped it with plain SQL, or restored the cluster from\n * a backup taken before it. The row is what `list` reads, so the branch goes\n * on being reported forever; `switch` and `info` then fail against a\n * database nothing can find.\n *\n * 2. **Orphan databases** — an `rb_*` database with no row. `createBranch`\n * creates the database first and records it second, so a crash between the\n * two leaves exactly this: disk consumed by something no Rebase command will\n * ever mention again.\n *\n * 3. **Expired branches** — alive, registered, and older than you meant to keep.\n * This is the ordinary case and the reason the command exists.\n *\n * Atlas's scratch databases are reported alongside but never removed by\n * default. `rebase db push` creates `<db>_dev_diff` to compute its diff against\n * and does not always clean it up, so they accumulate next to the branches and\n * look like them. They are not branches, and one may belong to an Atlas run\n * happening right now — so this names them and leaves the decision to a flag.\n */\n\n/** A branch as `rebase.branches` records it. */\nexport interface BranchRow {\n name: string;\n dbName: string;\n createdAt: Date;\n}\n\nexport interface PrunePlan {\n /** Registered, but the database is gone. Remove the row only. */\n staleRows: BranchRow[];\n /** An `rb_*` database with no row. Drop the database only. */\n orphanDatabases: string[];\n /** Alive, registered, older than the cutoff. Drop both. */\n expired: { branch: BranchRow; ageDays: number }[];\n /** Atlas scratch databases. Reported; removed only when asked. */\n devDiff: string[];\n}\n\n/** True when nothing at all needs doing. */\nexport function planIsEmpty(plan: PrunePlan, includeDevDiff: boolean): boolean {\n return plan.staleRows.length === 0\n && plan.orphanDatabases.length === 0\n && plan.expired.length === 0\n && (!includeDevDiff || plan.devDiff.length === 0);\n}\n\n/**\n * Age in whole days, floored.\n *\n * Floored rather than rounded so `--older-than 7` never catches something six\n * and a half days old: a prune that removes more than it said it would is worse\n * than one that waits another twelve hours.\n */\nexport function ageInDays(createdAt: Date, now: Date): number {\n return Math.floor((now.getTime() - createdAt.getTime()) / 86_400_000);\n}\n\n/**\n * Parse `--older-than`. Accepts a bare number of days, or `7d` / `2w`.\n *\n * Returns null for anything else, so the caller refuses rather than guessing —\n * silently reading `--older-than 7h` as seven *days* would delete a week of\n * work.\n */\nexport function parseOlderThan(value: string): number | null {\n const match = /^(\\d+)\\s*([dw])?$/i.exec(value.trim());\n if (!match) return null;\n\n const amount = Number(match[1]);\n if (!Number.isFinite(amount)) return null;\n\n return match[2]?.toLowerCase() === \"w\" ? amount * 7 : amount;\n}\n\nexport function planPrune(\n input: {\n rows: readonly BranchRow[];\n /** Every database name on the server. */\n databases: readonly string[];\n branchPrefix: string;\n },\n options: { olderThanDays?: number | null; now?: Date } = {}\n): PrunePlan {\n const now = options.now ?? new Date();\n const present = new Set(input.databases);\n const registered = new Set(input.rows.map((row) => row.dbName));\n\n const staleRows = input.rows.filter((row) => !present.has(row.dbName));\n\n const orphanDatabases = input.databases\n .filter((name) => name.startsWith(input.branchPrefix) && !registered.has(name))\n .sort();\n\n const expired = options.olderThanDays == null\n ? []\n : input.rows\n // A row whose database is already gone is a stale row, not an\n // expired branch — listing it under both would offer to drop a\n // database that does not exist.\n .filter((row) => present.has(row.dbName))\n .map((branch) => ({ branch, ageDays: ageInDays(branch.createdAt, now) }))\n .filter((entry) => entry.ageDays >= options.olderThanDays!)\n .sort((a, b) => b.ageDays - a.ageDays);\n\n const devDiff = input.databases.filter((name) => name.endsWith(\"_dev_diff\")).sort();\n\n return { staleRows, orphanDatabases, expired, devDiff };\n}\n","import arg from \"arg\";\nimport chalk from \"chalk\";\nimport { execa } from \"execa\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport { fileURLToPath } from \"url\";\nimport { logger } from \"@rebasepro/server\";\nimport { out, outWarn, outError } from \"./cli-output\";\nimport { formatRelativeTime } from \"@rebasepro/utils\";\nimport {\n diagnoseMissingBin,\n detectProjectPackageManager,\n describeBuildScriptRemedy,\n describeDevAddCommand,\n describeReinstallCommand,\n resolveLocalBin,\n getTableIncludes,\n getDevDatabaseUrl,\n ensureDevDatabaseExists,\n dropDevDatabase,\n applySearchDdl,\n getSearchExcludes,\n readSearchDdl,\n applyVectorDdl,\n getVectorExcludes,\n readVectorDdl,\n applyTriggersDdl,\n getTriggerExcludes,\n readTriggersDdl,\n getTableExcludes,\n getForeignIndexExcludes,\n ExcludeIntrospectionError,\n promptConfirm,\n queryGeneratedColumnDependencies,\n dropGeneratedColumns,\n loadCollectionsForCli\n} from \"./cli-helpers\";\nimport {\n checkDatabaseConnectivity,\n diagnoseAtlasFailure,\n diagnoseDbError,\n formatForeignGeneratedColumnBanner,\n reportCommandFailure\n} from \"./cli-errors\";\nimport { forLibpq } from \"./utils/connection-string\";\nimport { dropLegacyAuthSchema, RLS_BOOTSTRAP_SQL } from \"./schema/rls-bootstrap-sql\";\nimport { detectDestructiveStatements, decidePushSafety } from \"./schema/destructive-sql\";\nimport {\n parseColumnMutations,\n findGeneratedColumnConflicts,\n partitionByOwnership,\n dropGeneratedColumnStatements,\n migrationDropPreamble,\n describeConflict\n} from \"./schema/generated-column-conflicts\";\nimport { stripCarvedOutStatements } from \"./schema/carved-out-migration\";\nimport { acceptsExcludeFlag, buildAtlasArgs } from \"./schema/atlas-argv\";\nimport { unexpectedBranchArgs } from \"./branch-argv\";\nimport { assertKnownFlags, collectionsPathIn } from \"./cli-flags\";\nimport { assertCollectionsPathExists } from \"./cli-collections-path\";\nimport { backupActionOf } from \"./backup-argv\";\n\nimport { planIsEmpty, planPrune, parseOlderThan } from \"./branch-prune\";\n\nconst __cliDirname = path.dirname(fileURLToPath(import.meta.url));\n\n/**\n * A script this CLI spawns, and how to run it.\n *\n * Four commands — `schema generate`, the DDL plan, `introspect` and the schema\n * doctor — run as child processes, located by path relative to this file. That\n * path used to be `<dir>/schema/<name>.ts`, which worked only because `files`\n * shipped `src`. When the tarball stopped shipping `src`, every one of those\n * commands broke for every npm consumer at once: the file was simply absent,\n * and the parent CLI reported the absence as \"Dependencies are not installed\"\n * at projects that had installed perfectly. 0.18.0 shipped that way — a\n * scaffolded project's first `rebase dev` could not regenerate its schema and\n * every `GET /api/data/*` answered `Table not found for collection 'posts'`.\n *\n * The build emits each of them beside this file, so a published copy carries\n * the command surface as an artifact. Source still wins where there is no\n * build, which is how the monorepo runs before `pnpm build`.\n *\n * **The interpreter is tsx either way, and that is not incidental.** These\n * scripts load the *project's* collection files, which are TypeScript and\n * import each other as `./authors.js` — the extension TypeScript tells you to\n * write. Node resolves that literally and fails on a file that does not exist;\n * tsx maps it back. Running the built `.js` under plain `node` therefore fails\n * on the user's code rather than on ours, one directory further from anything\n * the error mentions.\n */\nfunction resolveChildScript(name: string):\n | { ok: true; bin: string; script: string }\n | { ok: false; reason: \"script\" | \"tsx\" } {\n const built = path.join(__cliDirname, \"schema\", `${name}.js`);\n const source = path.join(__cliDirname, \"schema\", `${name}.ts`);\n const script = fs.existsSync(built) ? built : fs.existsSync(source) ? source : null;\n if (!script) return { ok: false, reason: \"script\" };\n\n const tsxBin = resolveLocalBin(\"tsx\");\n if (!tsxBin) return { ok: false, reason: \"tsx\" };\n\n return { ok: true, bin: tsxBin, script };\n}\n\n/** What to print when {@link resolveChildScript} cannot produce a command. */\nfunction childScriptError(what: string, reason: \"script\" | \"tsx\"): string {\n if (reason === \"tsx\") {\n return `✗ Could not find the tsx binary, which ${what} needs to read your collection files. `\n + \"Install your project's dependencies and try again.\";\n }\n return `✗ The driver's ${what} is missing. This copy of @rebasepro/server-postgres is `\n + \"incomplete — reinstall it, or run its build if you are working in the monorepo.\";\n}\n\n\n\nasync function loadEnv(): Promise<void> {\n try {\n const dotenv = await import(\"dotenv\");\n const envPaths = [\n process.env.DOTENV_CONFIG_PATH,\n path.resolve(process.cwd(), \".env\"),\n path.resolve(process.cwd(), \"../.env\"),\n path.resolve(process.cwd(), \"../../.env\")\n ].filter(Boolean) as string[];\n\n for (const p of envPaths) {\n if (fs.existsSync(p)) {\n const parsed = dotenv.config({ path: p, quiet: true });\n if (parsed.parsed) {\n for (const [key, val] of Object.entries(parsed.parsed)) {\n if (process.env[key] === undefined) {\n process.env[key] = val;\n }\n }\n break;\n }\n }\n }\n } catch {\n // ignore\n }\n}\n\nexport async function runPluginCommand(args: string[]) {\n // Also set as an environment variable, not just per `config()` call: this\n // command spawns `tsx` subprocesses (the schema generator, the DDL\n // generator, doctor) that load `.env` themselves, and they inherit this.\n // dotenv reads it before `options.quiet`; an explicit `false` still wins.\n if (process.env.DOTENV_CONFIG_QUIET === undefined) {\n process.env.DOTENV_CONFIG_QUIET = \"true\";\n }\n await loadEnv();\n const domain = args[0]; // \"db\" or \"schema\"\n const subcommand = args[1];\n\n // Before anything reads the line: every parser below runs `permissive`,\n // which turns an undeclared flag into a positional rather than an error, so\n // `db push --alow-destructive` pushed with the destructive gate still shut\n // and `schema generate --ouput x` wrote the default path in silence. See\n // cli-flags.ts for why the check has to be here and not in those parsers.\n assertKnownFlags(domain, subcommand, args);\n\n // And before anything is generated: a `--collections` path that does not\n // resolve used to warn and carry on, four times over, and the generators\n // then wrote an *empty* schema over `drizzle/schema.sql` and\n // `src/schema.generated.ts` — both committed artifacts — after which the\n // push planned a DROP TABLE for every table in the database. Only the\n // destructive gate stood between a typo and the whole schema.\n //\n // Checked here rather than in `loadCollectionsForCli`, which is\n // deliberately forgiving: its callers use it to *narrow* what Atlas may\n // touch, and a hard failure there would block a push over one broken file.\n // This is a different question — \"does the directory the user named\n // exist\" — and the answer was already known before the first write.\n assertCollectionsPathExists(collectionsPathIn(args));\n\n if (domain === \"db\") {\n await dbCommand(subcommand, args);\n } else if (domain === \"schema\") {\n await schemaCommand(subcommand, args);\n } else if (domain === \"doctor\") {\n await doctorPluginCommand(args);\n } else {\n outError(chalk.red(`Unknown domain command: ${domain}`));\n process.exit(1);\n }\n}\n\n/** The migration files on disk, sorted, or none if the directory is absent. */\nfunction listMigrationFiles(): string[] {\n const dir = path.resolve(process.cwd(), \"drizzle\", \"migrations\");\n if (!fs.existsSync(dir)) return [];\n return fs.readdirSync(dir).filter(f => f.endsWith(\".sql\")).sort();\n}\n\n/**\n * The newest migration's version — the numeric prefix Atlas records.\n *\n * `20260906101530_init.sql` → `20260906101530`. Named in the baseline remedy so\n * the command it prints can be typed rather than worked out.\n */\nfunction latestMigrationVersion(): string | null {\n const newest = listMigrationFiles().at(-1);\n if (!newest) return null;\n const match = /^(\\d+)/.exec(newest);\n return match ? match[1] : newest.replace(/\\.sql$/, \"\");\n}\n\n/**\n * Take Atlas's carve-outs back out of the migration `migrate diff` just wrote.\n *\n * The apply path hands Atlas `--exclude` and it never sees the search or vector\n * columns. The diff path has no such flag — `atlas migrate diff` rejects\n * `--exclude` outright, and an `atlas.hcl` `env` block's `exclude` is accepted\n * and then ignored — so Atlas replays the migration directory (which builds\n * both columns, because that DDL is appended to migrations), does not find them\n * in `schema.sql`, and plans `DROP COLUMN`. Applied, that would take search and\n * the embeddings away from every database the migration reaches.\n *\n * Returns whether a migration Atlas just wrote is still there afterwards: a\n * file whose only content was the spurious drop is deleted, because an empty\n * migration is worse than none — it takes a slot in the revision history and\n * the caller would append the carved-out DDL and the policies to it.\n *\n * @returns true when a new migration survives and may be appended to.\n */\nasync function stripCarvedOutFromNewestMigration(collectionsPath: string): Promise<boolean> {\n // Both carve-outs, for one reason: they are the same problem. Search is out\n // of Atlas's sight because its free tier will not parse a function; vector\n // is out because Atlas resolves the desired state in a dev database that\n // can never have pgvector. What follows from that is identical — the diff\n // replays a migration directory holding objects `schema.sql` omits, and\n // plans a drop for every one.\n const patterns = [\n ...await getSearchExcludes(collectionsPath),\n ...await getVectorExcludes(collectionsPath),\n ...await getTriggerExcludes(collectionsPath)\n ];\n if (patterns.length === 0) return true;\n\n const newest = listMigrationFiles().at(-1);\n if (!newest) return false;\n const file = path.resolve(process.cwd(), \"drizzle\", \"migrations\", newest);\n\n const result = stripCarvedOutStatements(fs.readFileSync(file, \"utf-8\"), patterns);\n\n // Fail CLOSED, and loudly. A drop this could not rewrite stays in the file\n // exactly as Atlas wrote it, and the file is one somebody applies next week\n // — by which time the column is gone and nothing connects it to this run.\n // The destructive gate does not cover it either: that reads the *push*\n // plan. So `db generate` stops here rather than hand back a migration that\n // destroys a column the developer never asked to lose.\n if (result.unhandled.length > 0) {\n outError(chalk.red(\n `\\n ✗ ${newest} drops an object Rebase manages outside Atlas, in a form the CLI`\n ));\n outError(chalk.red(\" could not remove:\"));\n for (const statement of result.unhandled) {\n outError(chalk.gray(` ${statement.replace(/\\s+/g, \" \")}`));\n }\n outError(chalk.gray(\n \" Left as Atlas wrote it. Delete those statements by hand before running\\n\" +\n \" `rebase db migrate` — and please report them: rewriting this is meant to\\n\" +\n \" be automatic.\"\n ));\n process.exit(1);\n }\n\n if (result.removed.length === 0) return true;\n\n if (result.empty) {\n fs.rmSync(file);\n out(chalk.gray(\n ` ✓ Dropped ${newest} — it planned nothing but the removal of columns\\n` +\n \" Atlas cannot see and Rebase applies itself.\"\n ));\n } else {\n fs.writeFileSync(file, result.sql, \"utf-8\");\n out(chalk.gray(` ✓ Kept Rebase's own columns out of ${newest} (${result.removed.length} statement(s))`));\n }\n\n await runAtlas(\"migrate\", [\"hash\", \"--dir\", \"file://drizzle/migrations\"], collectionsPath);\n return !result.empty;\n}\n\nasync function dbCommand(subcommand: string, rawArgs: string[]): Promise<void> {\n const VALID_ACTIONS = [\"push\", \"generate\", \"migrate\", \"branch\", \"backup\", \"restore\", \"backups\"];\n if (!subcommand || !VALID_ACTIONS.includes(subcommand)) {\n outError(chalk.red(`Unknown db command. Valid: ${VALID_ACTIONS.join(\", \")}`));\n process.exit(1);\n }\n\n // A second line of defence, and not a redundant one. `rebase db` answers\n // `--help` before it ever spawns this file, but this file is also its own\n // CLI — the driver is spawned directly by `resolvePluginCliScript`, and is\n // executable on its own — so a `--help` reaching here means nobody upstream\n // caught it. Only `branch` had a case for it; `push`, `migrate` and\n // `restore` all took `--help` as an ordinary flag and did the work.\n if (rawArgs.includes(\"--help\") || rawArgs.includes(\"-h\")) {\n out(\"\");\n out(chalk.bold(` rebase db ${subcommand}`));\n out(chalk.gray(\" Run `rebase db --help` for the full page — this is the driver's own entry point.\"));\n out(\"\");\n return;\n }\n\n if (subcommand === \"branch\") {\n await branchCommand(rawArgs);\n return;\n }\n\n if (subcommand === \"backup\" || subcommand === \"restore\" || subcommand === \"backups\") {\n const { backupCommand, restoreCommand, backupsCommand } = await import(\"./backup/backup-cli\");\n // `rebase cloud db backup list` is how the cloud family spells this, and\n // locally the same words *created a backup*: \"list\" was a positional\n // `backupCommand` ignored. One CLI, two spellings, and the wrong guess\n // wrote a dump instead of reading one. Both spellings list now.\n if (subcommand === \"backup\" && backupActionOf(rawArgs) === \"list\") await backupsCommand(rawArgs);\n else if (subcommand === \"backup\") await backupCommand(rawArgs);\n else if (subcommand === \"restore\") await restoreCommand(rawArgs);\n else await backupsCommand(rawArgs);\n return;\n }\n\n const argsList = arg(\n {\n \"--collections\": String,\n \"--allow-destructive\": Boolean,\n \"--dry-run\": Boolean,\n \"--yes\": Boolean,\n \"--baseline\": String,\n \"-c\": \"--collections\",\n \"-y\": \"--yes\"\n },\n {\n argv: rawArgs.slice(2),\n permissive: true\n }\n );\n const collectionsPath = argsList[\"--collections\"] || path.join(\"..\", \"config\", \"collections\");\n\n if (subcommand === \"generate\") {\n out(\"\");\n out(chalk.bold(\" 📦 Rebase DB Generate\"));\n out(chalk.gray(\" Step 1/2: Generating Drizzle schema & Postgres DDL from collections...\"));\n out(\"\");\n await schemaCommand(\"generate\", rawArgs);\n await generatePostgresDdlCommand(rawArgs);\n out(\"\");\n out(chalk.gray(\" Step 2/2: Generating SQL migration files with Atlas...\"));\n out(\"\");\n const migrationName = argsList._[0] || \"migration\";\n const migrationsBefore = listMigrationFiles();\n await runAtlas(\"migrate\", [\"diff\", migrationName, \"--dir\", \"file://drizzle/migrations\", \"--to\", \"file://drizzle/schema.sql\"], collectionsPath);\n // The diff cannot be told to ignore the carved-out objects the way the\n // apply can, so the drop it plans for them is taken back out of the\n // file it just wrote. A migration that was nothing else is deleted.\n let wroteNewMigration = listMigrationFiles().length > migrationsBefore.length;\n if (wroteNewMigration) {\n wroteNewMigration = await stripCarvedOutFromNewestMigration(collectionsPath);\n }\n \n // Post-process the migration Atlas just wrote.\n //\n // `wroteNewMigration` gates the whole block, and that gate is the point.\n // \"The newest migration file\" is only Atlas's when Atlas wrote one;\n // otherwise it is a migration that has already run in production, and\n // appending to it changes a hash Atlas has recorded while the appended\n // SQL never runs anywhere. The search half already said so and checked;\n // the `CREATE SCHEMA` rewrite and the policy append did not, so every\n // `db generate` that found nothing to diff still grew the last\n // migration by another copy of the policies.\n try {\n const migrationsDir = path.resolve(process.cwd(), \"drizzle\", \"migrations\");\n if (fs.existsSync(migrationsDir) && wroteNewMigration) {\n const files = fs.readdirSync(migrationsDir);\n const sqlFiles = files\n .filter(f => f.endsWith(\".sql\"))\n .sort();\n if (sqlFiles.length > 0) {\n const newestMigrationFile = path.join(migrationsDir, sqlFiles[sqlFiles.length - 1]);\n\n // Make CREATE SCHEMA idempotent so it doesn't conflict with\n // --revisions-schema (Atlas pre-creates the rebase schema\n // for its revision table before running migrations).\n let migrationContent = fs.readFileSync(newestMigrationFile, \"utf-8\");\n migrationContent = migrationContent.replace(\n /CREATE SCHEMA (?!IF NOT EXISTS)(\"[^\"]+\");/g,\n \"CREATE SCHEMA IF NOT EXISTS $1;\"\n );\n // Atlas never writes the search or vector objects into a\n // migration — it is not shown them — so a migration\n // replayed against a fresh database would build every table\n // except the parts that make search and vector search work.\n // Appending, because these are `ALTER TABLE ... ADD COLUMN`\n // over the tables the migration just created.\n //\n // Vector first: `vector.sql` may open with\n // `CREATE EXTENSION vector`, so prerequisites lead, which is\n // the order a reader of the migration expects. Nothing in\n // search depends on it either way.\n const vectorContent = readVectorDdl();\n if (vectorContent) {\n migrationContent = `${migrationContent}\\n\\n${vectorContent}`;\n out(chalk.gray(\" ✓ Appended vector DDL to the migration\"));\n }\n\n const searchContent = readSearchDdl();\n if (searchContent) {\n // The same refusal `db push` works around, but decided\n // here and written into the file: this migration runs\n // later, somewhere else, against a database nobody can\n // inspect from this machine. A column retyped by the\n // statements above cannot be retyped while the search\n // column reads it, and the appended DDL below runs too\n // late to help — so the drop is prepended and the\n // rebuild is the append that was already happening.\n //\n // Derived from the collections rather than a catalogue:\n // `searchColumnDependencies` knows which columns each\n // block reads, which is all the decision needs.\n const { searchColumnDependencies } = await import(\"./schema/generate-postgres-ddl-logic\");\n const migrationConflicts = findGeneratedColumnConflicts(\n parseColumnMutations(migrationContent),\n searchColumnDependencies(await loadCollectionsForCli(collectionsPath))\n );\n const preamble = migrationDropPreamble(migrationConflicts);\n if (preamble) {\n migrationContent = `${preamble}\\n${migrationContent}`;\n for (const conflict of migrationConflicts) {\n out(chalk.gray(` ✓ ${describeConflict(conflict)} is dropped and rebuilt inside the migration`));\n }\n }\n migrationContent = `${migrationContent}\\n\\n${searchContent}`;\n out(chalk.gray(\" ✓ Appended search DDL to the migration\"));\n }\n\n // Last of the three: a trigger needs its table and its\n // column, and both arrive above.\n const triggersContent = readTriggersDdl();\n if (triggersContent) {\n migrationContent = `${migrationContent}\\n\\n${triggersContent}`;\n out(chalk.gray(\" ✓ Appended `updated_at` triggers to the migration\"));\n }\n\n fs.writeFileSync(newestMigrationFile, migrationContent, \"utf-8\");\n\n // Append RLS policies, preceded by the RLS bootstrap so the\n // migration is self-contained: Atlas replays migrations\n // against a clean dev database where `rebase.uid()` would\n // not otherwise exist.\n const policiesFile = path.resolve(process.cwd(), \"drizzle\", \"policies.sql\");\n if (fs.existsSync(policiesFile)) {\n const policiesContent = fs.readFileSync(policiesFile, \"utf-8\");\n fs.appendFileSync(newestMigrationFile, \"\\n\\n\" + RLS_BOOTSTRAP_SQL + \"\\n\" + policiesContent);\n out(chalk.gray(` ✓ Appended RLS policies to migration file: ${path.basename(newestMigrationFile)}`));\n\n // Re-hash the migration directory\n out(chalk.gray(\" Re-hashing migration files...\"));\n await runAtlas(\"migrate\", [\"hash\", \"--dir\", \"file://drizzle/migrations\"], collectionsPath);\n out(chalk.gray(\" ✓ Migration directory checksum updated successfully.\"));\n }\n }\n }\n } catch (err) {\n outWarn(chalk.yellow(` ⚠️ Failed to append policies or re-hash migration: ${err instanceof Error ? err.message : String(err)}`));\n }\n\n if (!wroteNewMigration) {\n // Reachable whenever the only thing that changed is something Atlas\n // cannot see — a `search` block, a `vector` property, or a\n // `securityRules` edit. There is no new file to carry it, and the\n // previous migration must not be reopened: it has already run\n // wherever this project is deployed.\n out(chalk.gray(\n \" ℹ No migration written — nothing in this change is visible to Atlas.\\n\" +\n \" Search, vector, trigger and RLS DDL are applied by `rebase db push`, and at\\n\" +\n \" boot by the schema ensure. For a migration-only deployment, add\\n\" +\n \" drizzle/search.sql, drizzle/vector.sql, drizzle/triggers.sql and\\n\" +\n \" drizzle/policies.sql to a migration by hand.\"\n ));\n }\n\n out(\"\");\n out(` You can now run ${chalk.bold.green(\"rebase db migrate\")} to apply the migrations to your database.`);\n out(\"\");\n } else {\n out(\"\");\n out(chalk.bold(` 🗄️ Rebase DB ${subcommand.charAt(0).toUpperCase() + subcommand.slice(1)}`));\n out(\"\");\n\n if (subcommand === \"push\") {\n out(chalk.gray(\" Step 1/3: Generating Drizzle schema & Postgres DDL from collections...\"));\n out(\"\");\n await schemaCommand(\"generate\", rawArgs);\n await generatePostgresDdlCommand(rawArgs);\n out(\"\");\n const dryRun = argsList[\"--dry-run\"] === true;\n out(chalk.gray(dryRun\n ? \" Step 2/3: Planning the change against the database (nothing is applied)...\"\n : \" Step 2/3: Pushing schema to database with Atlas...\"));\n out(\"\");\n const databaseUrl = process.env.DATABASE_URL;\n // Skipped under --dry-run: this creates the auth schema and its\n // functions, which is a write. \"Show me what would happen\" that\n // changes something on the way is not a plan.\n if (databaseUrl && !dryRun) {\n await ensureAuthSchemaAndFunctions(databaseUrl);\n }\n\n // Preview the plan before touching data. `atlas schema apply` with\n // --auto-approve will silently DROP COLUMN on a field removal and\n // drop+add on a rename, so we first dry-run to obtain the planned\n // SQL and gate anything destructive.\n const plan = await runAtlas(\n \"schema\",\n [\"apply\", \"--to\", \"file://drizzle/schema.sql\", \"--dry-run\"],\n collectionsPath,\n { captureStdout: true }\n );\n const destructive = detectDestructiveStatements(plan);\n\n // A generated column makes every column it reads immutable to\n // Atlas: PostgreSQL refuses `ALTER COLUMN … TYPE` and `DROP COLUMN`\n // while one depends on it, and `schema apply` runs its plan in a\n // single transaction — so one refusal rolls back the whole push,\n // including the statements that had nothing to do with it.\n //\n // Atlas cannot avoid planning it. The search column is hidden from\n // its view on purpose (`searchExcludePatterns`), because a desired\n // state that never mentions the column reads to Atlas as an\n // instruction to drop it. So the dependant is invisible exactly\n // where it would have to be visible.\n //\n // Rebase owns those columns, so it takes them out of the way and\n // `applySearchDdl` puts them back below — the same drop-and-re-apply\n // the search stamp guard already prescribes when a block changes.\n const generatedConflicts = databaseUrl\n ? findGeneratedColumnConflicts(\n parseColumnMutations(plan),\n await queryGeneratedColumnDependencies(databaseUrl)\n )\n : [];\n const { managed: rebuildable, foreign: unowned } = partitionByOwnership(\n generatedConflicts,\n collectionsPath ? await getSearchExcludes(collectionsPath) : []\n );\n\n // `--dry-run` stops here, having printed the SQL and nothing else.\n //\n // It exists because the only way to see this plan was to trigger\n // the destructive gate, and the gate prints the plan while exiting\n // 1 — so \"what would this do?\" was answerable only by a command\n // that looked like a failure, and unanswerable at all when the\n // change was additive. An agent with no way to show the SQL either\n // asks a human to approve something neither of them has read, or\n // runs the push to find out.\n if (dryRun) {\n out(chalk.gray(\" Step 3/3: --dry-run — nothing was applied.\"));\n out(\"\");\n if (plan.trim()) {\n out(chalk.bold(\" Planned changes:\"));\n out(chalk.gray(plan.trim().split(\"\\n\").map((l) => ` ${l}`).join(\"\\n\")));\n } else {\n out(chalk.green(\" ✓ No changes: the database already matches these collections.\"));\n }\n out(\"\");\n if (rebuildable.length > 0) {\n out(chalk.gray(` ${rebuildable.length} generated column(s) would be dropped before the apply and`));\n out(chalk.gray(\" rebuilt from search.sql after it — Postgres cannot retype a column\"));\n out(chalk.gray(\" while one reads it:\"));\n for (const conflict of rebuildable) {\n out(chalk.gray(` ${describeConflict(conflict)}`));\n }\n out(\"\");\n }\n if (unowned.length > 0) {\n outWarn(formatForeignGeneratedColumnBanner(unowned));\n }\n if (destructive.length > 0) {\n outWarn(chalk.yellow(` ⚠️ ${destructive.length} of those DESTROY data:`));\n for (const d of destructive) {\n outWarn(chalk.red(` ${d.kind}: `) + chalk.gray(d.statement.replace(/\\s+/g, \" \")));\n }\n outWarn(\"\");\n outWarn(chalk.yellow(\" Applying them needs `rebase db push --allow-destructive`. Back up first: rebase db backup\"));\n outWarn(\"\");\n }\n out(chalk.gray(\" The auth schema step was skipped, because it writes. A real push runs it first.\"));\n out(\"\");\n return;\n }\n\n // Before the destructive gate, and separately from it: this is not a\n // change the operator can approve their way through. Rebase has no\n // copy of the expression, so there is nothing to put back.\n if (unowned.length > 0) {\n outError(formatForeignGeneratedColumnBanner(unowned));\n process.exit(1);\n }\n\n const allowDestructive = argsList[\"--allow-destructive\"] === true || argsList[\"--yes\"] === true;\n const decision = decidePushSafety({\n destructiveCount: destructive.length,\n allowDestructive,\n interactive: process.stdin.isTTY === true\n });\n\n if (destructive.length > 0) {\n outWarn(chalk.yellow(` ⚠️ This push includes ${destructive.length} destructive change(s) that will DESTROY data:`));\n outWarn(\"\");\n for (const d of destructive) {\n outWarn(chalk.red(` ${d.kind}: `) + chalk.gray(d.statement.replace(/\\s+/g, \" \")));\n }\n outWarn(\"\");\n outWarn(chalk.yellow(\" Full planned changes:\"));\n outWarn(chalk.gray(plan.trim().split(\"\\n\").map((l) => ` ${l}`).join(\"\\n\")));\n outWarn(\"\");\n\n if (decision === \"refuse\") {\n outError(chalk.red(\" ✗ Aborting: destructive changes require confirmation.\"));\n outError(chalk.gray(\" Re-run interactively, or pass --allow-destructive to proceed. Back up first: rebase db backup\"));\n process.exit(1);\n }\n if (decision === \"confirm\") {\n const confirmed = await promptConfirm(\n chalk.yellow(\" Type 'yes' to apply these destructive changes (this cannot be undone): \")\n );\n if (!confirmed) {\n out(chalk.gray(\" Aborted. No changes were made.\"));\n process.exit(1);\n }\n } else {\n // decision === \"apply\" via --allow-destructive\n outWarn(chalk.yellow(\" Proceeding because --allow-destructive was passed.\"));\n }\n }\n\n if (rebuildable.length > 0 && databaseUrl) {\n for (const conflict of rebuildable) {\n out(chalk.gray(` Dropping ${describeConflict(conflict)} — it reads a column this push retypes.`));\n }\n await dropGeneratedColumns(databaseUrl, dropGeneratedColumnStatements(rebuildable));\n }\n\n try {\n await runAtlas(\"schema\", [\"apply\", \"--to\", \"file://drizzle/schema.sql\", \"--auto-approve\"], collectionsPath);\n } catch (err) {\n // Atlas rolled its transaction back, so the columns those\n // expressions read are as they were and the definitions in\n // search.sql still fit. Put them back before surfacing the\n // failure: a push that fails must not also leave search broken.\n if (rebuildable.length > 0 && databaseUrl) {\n out(chalk.gray(\" The apply failed — rebuilding the generated columns it needed out of the way.\"));\n await applySearchDdl(databaseUrl);\n }\n throw err;\n }\n out(\"\");\n \n if (databaseUrl) {\n await ensureAuthTables(databaseUrl, collectionsPath);\n // After the tables exist and before the policies: the vector and\n // search columns are `ALTER TABLE ... ADD COLUMN`, and a policy\n // may reference the table they are added to.\n await applyVectorDdl(databaseUrl);\n await applySearchDdl(databaseUrl);\n await applyTriggersDdl(databaseUrl);\n await applyPolicies(databaseUrl);\n await reconcilePolicies(databaseUrl, collectionsPath);\n await ensureRlsUserRole(databaseUrl);\n await retireLegacyAuthSchema(databaseUrl);\n\n // The push worked, so the throwaway schema copy Atlas planned\n // against has nothing left to say. It was kept forever, one per\n // target, and the only notice was `rebase db branch prune`\n // reporting them. On a failed push we never reach this line —\n // deliberately: there the scratch database is the evidence.\n // And only the one this run created: a scratch database the\n // user made by hand is theirs to keep.\n if (scratchDatabaseCreatedHere) {\n await dropDevDatabase(databaseUrl, getDevDatabaseUrl(databaseUrl));\n }\n } else {\n outWarn(chalk.yellow(\" ⚠️ DATABASE_URL not found in environment, skipping RLS policies application.\"));\n }\n } else if (subcommand === \"migrate\") {\n const databaseUrl = process.env.DATABASE_URL;\n if (databaseUrl) {\n await ensureAuthSchemaAndFunctions(databaseUrl);\n }\n const extraArgs = argsList._.filter(arg => arg !== \"migrate\");\n // `--baseline <version>` is relayed to Atlas as its own: it records\n // the version as already applied and starts from the next one. The\n // database a Rebase boot has provisioned is exactly the case it is\n // for, and without it `migrate apply` there is unusable — see\n // `formatBaselineRemedy`, which is what prints when it is missing.\n const baseline = argsList[\"--baseline\"];\n if (baseline) {\n out(chalk.gray(` Recording ${baseline} as already applied, then migrating from the next one.`));\n out(\"\");\n }\n await runAtlas(\n \"migrate\",\n [\n \"apply\",\n \"--dir\", \"file://drizzle/migrations\",\n ...(baseline ? [\"--baseline\", baseline] : []),\n ...extraArgs\n ],\n collectionsPath\n );\n if (databaseUrl) {\n await ensureRlsUserRole(databaseUrl);\n await retireLegacyAuthSchema(databaseUrl);\n }\n }\n\n out(\"\");\n out(chalk.green(` ✓ rebase db ${subcommand} completed successfully.`));\n out(\"\");\n }\n}\n\nasync function ensureAuthSchemaAndFunctions(databaseUrl: string): Promise<void> {\n try {\n const { Client } = await import(\"pg\");\n const client = new Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n // Creates the `rebase` schema as its first statement, which also\n // covers the schema Atlas puts its revision table in\n // (`--revisions-schema rebase`). That used to need a separate,\n // deliberately migration-stream-excluded statement here, because the\n // helper functions lived in `auth` and creating `rebase` from the\n // preamble would have made Atlas plan a DROP for it. The generator\n // now always declares `rebase` in the desired schema, so there is\n // nothing to keep out.\n await client.query(RLS_BOOTSTRAP_SQL);\n } finally {\n await client.end();\n }\n } catch (err) {\n outWarn(chalk.yellow(` ⚠️ Failed to bootstrap the RLS helper functions: ${err instanceof Error ? err.message : String(err)}`));\n }\n}\n\n/**\n * Create the framework auth tables (e.g. `rebase.users`) that the generated RLS\n * policies reference, before `applyPolicies` runs. Mirrors what the server does\n * at boot (`PostgresBootstrapper.initializeAuth` → `ensureAuthTablesExist`).\n *\n * Without this, `rebase db push` against a database that has never booted the\n * server fails while applying policies with `relation \"rebase.users\" does not\n * exist` — the documented first-run does `db push` *before* the first `dev`.\n * `ensureAuthTablesExist` is idempotent (CREATE TABLE IF NOT EXISTS), so it is\n * safe to run on every push and harmless once the server has also created them.\n */\nasync function ensureAuthTables(databaseUrl: string, collectionsPath: string): Promise<void> {\n try {\n const { drizzle } = await import(\"drizzle-orm/node-postgres\");\n const { ensureAuthTablesExist } = await import(\"./auth/ensure-tables\");\n const { loadCollections } = await import(\"./schema/doctor\");\n const { Client } = await import(\"pg\");\n\n const collections = await loadCollections(path.resolve(process.cwd(), collectionsPath));\n // The auth collection is flagged with `auth: true` or `auth: { enabled: true }`.\n const authCollection = collections.find((c) => {\n const a = c.auth;\n return a === true || (typeof a === \"object\" && a !== null && a.enabled === true);\n });\n\n const client = new Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n await ensureAuthTablesExist(drizzle(client), authCollection);\n } finally {\n await client.end();\n }\n } catch (err) {\n outWarn(chalk.yellow(` ⚠️ Failed to ensure framework auth tables: ${err instanceof Error ? err.message : String(err)}`));\n }\n}\n\n/**\n * Provision the restricted `rebase_user` role right after schema changes land,\n * so grants cover freshly created tables (default privileges cover future\n * ones). Only needed — and only possible without extra setup — when the\n * connection would bypass RLS (superuser / BYPASSRLS / table owner).\n */\nasync function ensureRlsUserRole(databaseUrl: string): Promise<void> {\n // Every failure in here used to escape uncaught, and `db migrate`'s caller\n // turns that into a bare `process.exit(1)` — so the migration would apply,\n // print `-- ok`, and then the command would die with NO output whatsoever\n // and a non-zero status. Seen with a module-resolution error inside the\n // dynamic import, where the entire diagnosis was one silent exit code.\n //\n // Reported rather than rethrown, and deliberately not fatal: the schema\n // change has already landed at this point, so failing the command implies a\n // rollback that did not happen. What is actually lost is the role\n // provisioning, and the message says so and how to finish it by hand.\n // No `auth`: the RLS helpers live in `rebase` now, and a schema the\n // framework no longer creates must not be granted on — on a Supabase\n // database that would hand the end-user role USAGE on their auth schema.\n const schemas = [\"public\", \"rebase\"];\n let rls: typeof import(\"./security/rls-enforcement\");\n try {\n rls = await import(\"./security/rls-enforcement\");\n } catch (err) {\n // A module-resolution failure here is a build problem, not a database\n // one, and it is exactly the case that used to produce the silent exit.\n outError(chalk.red(\n `\\n ✗ Could not load the RLS provisioning module: ${err instanceof Error ? err.message : String(err)}`\n ));\n return;\n }\n\n try {\n const { Client } = await import(\"pg\");\n const client = new Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n const runSql = async (text: string) => (await client.query(text)).rows as Record<string, unknown>[];\n const posture = await rls.detectConnectionPosture(runSql);\n if (posture.privileged) {\n await rls.ensureAppRole(runSql, schemas);\n out(chalk.gray(` ✓ RLS role \"${rls.REBASE_USER_ROLE}\" provisioned/refreshed.`));\n }\n } finally {\n await client.end();\n }\n } catch (err) {\n outError(chalk.red(\n `\\n ✗ The schema change was applied, but the \"${rls.REBASE_USER_ROLE}\" role could not be ` +\n `provisioned: ${err instanceof Error ? err.message : String(err)}`\n ));\n outError(chalk.gray(rls.appRoleSetupInstructions(\"your database user\", schemas)));\n }\n}\n\n/**\n * Retire the pre-1.0 `auth` schema, once nothing depends on it any more.\n *\n * Runs last on purpose. Postgres refuses to drop a function an RLS policy still\n * calls, so this only succeeds after the policies above have been rewritten to\n * `rebase.uid()`. See `dropLegacyAuthSchema` for what it reports when something\n * hand-written is still holding the schema open, and DROP_LEGACY_AUTH_SCHEMA_SQL\n * for the guards that keep it off a Supabase `auth` schema.\n */\nasync function retireLegacyAuthSchema(databaseUrl: string): Promise<void> {\n try {\n const { Client } = await import(\"pg\");\n const client = new Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n await dropLegacyAuthSchema(\n async (text) => (await client.query(text)).rows as Record<string, unknown>[],\n {\n info: (m) => out(chalk.gray(` ${m}`)),\n warn: (m) => outWarn(chalk.yellow(` ⚠️ ${m}`))\n }\n );\n } finally {\n await client.end();\n }\n } catch {\n // Connection-level failure only; the schema is inert either way.\n }\n}\n\nasync function applyPolicies(databaseUrl: string): Promise<void> {\n try {\n const policiesPath = path.resolve(process.cwd(), \"drizzle\", \"policies.sql\");\n if (!fs.existsSync(policiesPath)) return;\n \n out(chalk.gray(\" Step 3/3: Applying RLS policies to database...\"));\n out(\"\");\n \n const policiesContent = fs.readFileSync(policiesPath, \"utf-8\");\n const { Client } = await import(\"pg\");\n const client = new Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n await client.query(policiesContent);\n out(chalk.green(\" ✓ RLS policies applied successfully.\"));\n } finally {\n await client.end();\n }\n } catch (err) {\n const hint = diagnoseDbError(err, databaseUrl);\n if (hint) {\n outError(hint);\n } else {\n outError(chalk.red(` ✗ Failed to apply RLS policies: ${err instanceof Error ? err.message : String(err)}`));\n }\n process.exit(1);\n }\n}\n\n/**\n * Remove the policies an earlier push superseded but never dropped.\n *\n * `policies.sql` only DROPs the names it is about to CREATE, and a rule's\n * generated name contains a hash of its own semantics — so editing a rule\n * writes a *new* policy and abandons the old one. Postgres ORs PERMISSIVE\n * policies together, which makes an abandoned grant outrank every tightening\n * that replaced it, and push reported success the whole time.\n *\n * Runs after `applyPolicies` so the current policies are already in place: the\n * drift check then sees exactly the set that should survive, and anything else\n * on a managed table is by definition left over.\n */\nasync function reconcilePolicies(databaseUrl: string, collectionsPath: string): Promise<void> {\n try {\n const { checkPolicyDrift, dropOrphanedPolicies, formatPolicyDrift, hasDrift } =\n await import(\"./security/policy-drift\");\n const { loadCollections } = await import(\"./schema/doctor\");\n\n const collections = await loadCollections(path.resolve(process.cwd(), collectionsPath));\n const { Client } = await import(\"pg\");\n const client = new Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n const drift = await checkPolicyDrift(client as never, collections);\n const { dropped, kept } = await dropOrphanedPolicies(client as never, drift, collections);\n\n for (const p of dropped) {\n out(chalk.gray(` ✓ Dropped superseded policy \"${p.name}\" on ${p.schema}.${p.table}`));\n }\n if (dropped.length > 0) {\n out(chalk.green(` ✓ Removed ${dropped.length} superseded RLS ${dropped.length === 1 ? \"policy\" : \"policies\"}.`));\n }\n\n // Custom-named orphans are indistinguishable from policies someone\n // wrote in SQL deliberately, so they are reported, never dropped.\n if (kept.length > 0) {\n outWarn(chalk.yellow(\" ⚠️ Policies in the database that no collection describes:\"));\n for (const p of kept) {\n outWarn(chalk.yellow(` • ${p.schema}.${p.table} → \"${p.name}\" (${p.command} TO ${p.roles.join(\", \")})`));\n }\n outWarn(chalk.yellow(\" These still grant access. Drop them by hand if they are stale.\"));\n }\n\n // Missing/diverged are not push's to fix, but staying silent about\n // them is how a database ends up not matching its config.\n const remaining = { ...drift, orphaned: kept };\n if (hasDrift(remaining) && (remaining.missing.length > 0 || remaining.diverged.length > 0)) {\n outWarn(chalk.yellow(\" ⚠️ RLS policies do not match your collections:\"));\n outWarn(formatPolicyDrift({ ...remaining, orphaned: [] }));\n }\n } finally {\n await client.end();\n }\n } catch (err) {\n outWarn(chalk.yellow(` ⚠️ Could not reconcile RLS policies: ${err instanceof Error ? err.message : String(err)}`));\n }\n}\n\n/**\n * Flags the `branch` subcommands take.\n *\n * Declared as an `arg` spec rather than picked out of argv by hand, which is\n * both how the rest of this file parses flags and how the documentation\n * verifier discovers them: it reads `arg({ … })` specs out of this source, so a\n * flag parsed any other way is one it reports as unrunnable in every page that\n * documents it. Hand-rolled parsing here cost exactly that — `--older-than`\n * worked and the docs check called it a command a reader cannot run.\n */\nconst BRANCH_FLAGS = {\n \"--older-than\": String,\n \"--include-dev-diff\": Boolean,\n \"--from\": String,\n \"--yes\": Boolean,\n \"-y\": \"--yes\"\n} as const;\n\nasync function branchCommand(rawArgs: string[]): Promise<void> {\n const branchAction = rawArgs[2]; // create, list, delete, info\n\n if (!branchAction || branchAction === \"--help\") {\n printBranchHelp();\n return;\n }\n\n // Before anything connects: a name that is not the name asked for is worth\n // refusing, and it costs a database round-trip to discover later.\n const extras = unexpectedBranchArgs(rawArgs.slice(2));\n if (extras.length > 0) {\n outError(\"\");\n outError(chalk.red(` ✗ Unexpected argument${extras.length > 1 ? \"s\" : \"\"}: ${extras.join(\" \")}`));\n outError(\"\");\n outError(chalk.gray(` ${chalk.bold(\"rebase db branch\")} takes one name. A branch name may contain letters,`));\n outError(chalk.gray(\" digits, underscores and hyphens — no spaces.\"));\n if (rawArgs[3]) {\n outError(chalk.gray(` Did you mean: ${chalk.cyan(`rebase db branch ${branchAction} ${[rawArgs[3], ...extras].join(\"-\")}`)}`));\n }\n outError(\"\");\n process.exit(1);\n }\n\n // Load .env for DATABASE_URL\n try {\n const dotenv = await import(\"dotenv\");\n const envPath = process.env.DOTENV_CONFIG_PATH;\n if (envPath) {\n dotenv.config({ path: envPath, quiet: true });\n } else {\n dotenv.config({ quiet: true });\n }\n } catch {\n // dotenv may not be installed\n }\n\n const databaseUrl = process.env.DATABASE_URL || process.env.ADMIN_CONNECTION_STRING;\n if (!databaseUrl) {\n outError(chalk.red(\"✗ DATABASE_URL is not set. Make sure your .env file is configured.\"));\n process.exit(1);\n }\n\n // Dynamic imports to avoid loading heavy deps when not needed\n const { DatabasePoolManager } = await import(\"./databasePoolManager\");\n const { BranchService } = await import(\"./services/BranchService\");\n const { drizzle } = await import(\"drizzle-orm/node-postgres\");\n const { Pool } = await import(\"pg\");\n\n const pool = new Pool({ connectionString: databaseUrl,\nmax: 3 });\n const db = drizzle(pool);\n const poolManager = new DatabasePoolManager(databaseUrl);\n const branchService = new BranchService(db, poolManager);\n\n // Ensure metadata table exists\n await branchService.ensureBranchMetadataTable();\n\n try {\n switch (branchAction) {\n case \"create\": {\n const name = rawArgs[3];\n if (!name) {\n outError(chalk.red(\"✗ Branch name is required.\"));\n out(chalk.gray(\" Usage: rebase db branch create <name> [--from <source>]\"));\n process.exit(1);\n }\n let source: string | undefined;\n const fromIdx = rawArgs.indexOf(\"--from\");\n if (fromIdx !== -1 && rawArgs[fromIdx + 1]) {\n source = rawArgs[fromIdx + 1];\n }\n const force = rawArgs.includes(\"--force\");\n out(\"\");\n out(chalk.bold(\" 🌿 Creating database branch...\"));\n out(chalk.gray(` Name: ${name}`));\n if (source) out(chalk.gray(` Source: ${source}`));\n if (force) out(chalk.gray(\" Force: other connections to the source will be disconnected\"));\n out(\"\");\n const branch = await branchService.createBranch(name, { source, force });\n out(chalk.green(` ✓ Branch \"${branch.name}\" created successfully.`));\n out(chalk.gray(` Database: rb_${branch.name}`));\n out(chalk.gray(` Parent: ${branch.parentDatabase}`));\n out(\"\");\n break;\n }\n\n case \"list\": {\n const branches = await branchService.listBranches();\n out(\"\");\n if (branches.length === 0) {\n out(chalk.gray(\" No branches found. Create one with: rebase db branch create <name>\"));\n } else {\n out(chalk.bold(` 🌿 ${branches.length} branch(es):`));\n out(\"\");\n for (const b of branches) {\n const size = b.sizeBytes != null\n ? chalk.gray(` (${formatBytes(b.sizeBytes)})`)\n : \"\";\n const age = chalk.gray(` — created ${timeAgo(b.createdAt)}`);\n out(` ${chalk.green(\"●\")} ${chalk.bold(b.name)}${size}${age}`);\n out(chalk.gray(` from ${b.parentDatabase}`));\n }\n }\n out(\"\");\n break;\n }\n\n case \"delete\": {\n const name = rawArgs[3];\n if (!name) {\n outError(chalk.red(\"✗ Branch name is required.\"));\n out(chalk.gray(\" Usage: rebase db branch delete <name>\"));\n process.exit(1);\n }\n out(\"\");\n out(chalk.bold(` 🗑️ Deleting branch \"${name}\"...`));\n await branchService.deleteBranch(name, { force: rawArgs.includes(\"--force\") });\n out(chalk.green(` ✓ Branch \"${name}\" deleted.`));\n out(\"\");\n break;\n }\n\n case \"info\": {\n const name = rawArgs[3];\n if (!name) {\n outError(chalk.red(\"✗ Branch name is required.\"));\n out(chalk.gray(\" Usage: rebase db branch info <name>\"));\n process.exit(1);\n }\n const info = await branchService.getBranchInfo(name);\n out(\"\");\n if (!info) {\n // Exit 1, like `delete` on a branch that is not there.\n // These two answered the same question — \"is there a branch\n // called this?\" — and disagreed about how to say no: delete\n // failed, info printed `✗ Branch \"x\" not found.` and exited\n // 0. Anything reading the status saw success, so\n // `rebase db branch info \"$b\" && deploy_against \"$b\"` ran\n // the deploy against a branch that does not exist.\n outError(chalk.red(` ✗ Branch \"${name}\" not found.`));\n out(\"\");\n process.exit(1);\n } else {\n out(chalk.bold(` 🌿 Branch: ${info.name}`));\n out(chalk.gray(` Database: rb_${info.name}`));\n out(chalk.gray(` Parent: ${info.parentDatabase}`));\n out(chalk.gray(` Created: ${info.createdAt.toISOString()}`));\n if (info.sizeBytes != null) {\n out(chalk.gray(` Size: ${formatBytes(info.sizeBytes)}`));\n }\n }\n out(\"\");\n break;\n }\n\n case \"prune\": {\n const parsed = arg(BRANCH_FLAGS, { argv: rawArgs.slice(3), permissive: true });\n const olderThanRaw = parsed[\"--older-than\"] ?? null;\n const olderThanDays = olderThanRaw == null ? null : parseOlderThan(olderThanRaw);\n if (olderThanRaw != null && olderThanDays == null) {\n outError(chalk.red(` ✗ --older-than \"${olderThanRaw}\" is not a duration.`));\n out(chalk.gray(\" Use a number of days (14), or 14d / 2w.\"));\n process.exit(1);\n }\n\n const includeDevDiff = parsed[\"--include-dev-diff\"] === true;\n const { rows, databases } = await branchService.pruneCandidates();\n const plan = planPrune({ rows, databases, branchPrefix: \"rb_\" }, { olderThanDays });\n\n out(\"\");\n if (planIsEmpty(plan, includeDevDiff)) {\n out(chalk.gray(\" Nothing to prune.\"));\n if (!olderThanDays && rows.length > 0) {\n out(chalk.gray(` ${rows.length} branch(es) are healthy — --older-than 14 also removes old ones.`));\n }\n if (!includeDevDiff && plan.devDiff.length > 0) {\n out(chalk.gray(` ${plan.devDiff.length} Atlas scratch database(s) left over from db push;`));\n out(chalk.gray(\" --include-dev-diff removes those too.\"));\n }\n out(\"\");\n break;\n }\n\n out(chalk.bold(\" 🧹 Prune plan\"));\n out(\"\");\n for (const row of plan.staleRows) {\n out(` ${chalk.yellow(\"○\")} ${chalk.bold(row.name)} ${chalk.gray(\"— registered, but its database is gone; the entry will be removed\")}`);\n }\n for (const dbName of plan.orphanDatabases) {\n out(` ${chalk.yellow(\"○\")} ${chalk.bold(dbName)} ${chalk.gray(\"— a branch database with no entry; the database will be dropped\")}`);\n }\n for (const { branch, ageDays } of plan.expired) {\n out(` ${chalk.red(\"●\")} ${chalk.bold(branch.name)} ${chalk.gray(`— ${ageDays} days old; branch and database will be dropped`)}`);\n }\n if (includeDevDiff) {\n for (const dbName of plan.devDiff) {\n out(` ${chalk.red(\"●\")} ${chalk.bold(dbName)} ${chalk.gray(\"— Atlas scratch database; will be dropped\")}`);\n }\n } else if (plan.devDiff.length > 0) {\n out(chalk.gray(` (${plan.devDiff.length} Atlas scratch database(s) not listed — --include-dev-diff)`));\n }\n out(\"\");\n\n if (parsed[\"--yes\"] !== true) {\n // Dropping a database is not undoable and a branch may be\n // the only copy of an afternoon's work.\n const confirmed = await promptConfirm(\" Remove these? (y/N) \");\n if (!confirmed) {\n out(chalk.gray(\" Nothing was changed.\"));\n out(\"\");\n break;\n }\n }\n\n let removed = 0;\n for (const row of plan.staleRows) {\n await branchService.forgetBranchRow(row.name);\n removed += 1;\n }\n for (const dbName of plan.orphanDatabases) {\n await branchService.dropDatabase(dbName);\n removed += 1;\n }\n for (const { branch } of plan.expired) {\n await branchService.deleteBranch(branch.name);\n removed += 1;\n }\n if (includeDevDiff) {\n for (const dbName of plan.devDiff) {\n await branchService.dropDatabase(dbName);\n removed += 1;\n }\n }\n\n out(chalk.green(` ✓ Pruned ${removed} item(s).`));\n out(\"\");\n break;\n }\n\n default:\n outError(chalk.red(`Unknown branch action: \"${branchAction}\".`));\n printBranchHelp();\n process.exit(1);\n }\n } finally {\n await poolManager.shutdown();\n await pool.end();\n }\n}\n\nfunction printBranchHelp() {\n out(`\n${chalk.bold(\"rebase db branch\")} — Database branching commands\n\n${chalk.green.bold(\"Usage\")}\n rebase db branch ${chalk.blue(\"<command>\")} [options]\n\n${chalk.green.bold(\"Commands\")}\n ${chalk.blue.bold(\"create\")} <name> [--from <source>] Create a new branch\n ${chalk.blue.bold(\"list\")} List all branches\n ${chalk.blue.bold(\"switch\")} [<name>|--off] Point this checkout at a branch\n ${chalk.blue.bold(\"delete\")} <name> Delete a branch\n ${chalk.blue.bold(\"info\")} <name> Show branch details\n ${chalk.blue.bold(\"prune\")} [--older-than <14|14d|2w>] Remove branches nothing is using\n\n${chalk.green.bold(\"Why prune\")}\n Every branch is a full-size copy — CREATE DATABASE ... TEMPLATE duplicates the\n files on disk, so five branches of a 100GB database cost 500GB. Prune also\n finds the two ways branches drift: an entry whose database was dropped\n outside Rebase, and a branch database whose entry never got written.\n\n${chalk.green.bold(\"Options\")}\n ${chalk.blue.bold(\"--force\")} Disconnect other sessions first.\n Postgres refuses to copy or drop a database\n anything else is connected to — usually your\n own \\`rebase dev\\`.\n ${chalk.blue.bold(\"--include-dev-diff\")} Also prune the Atlas scratch databases\n \\`db push\\` leaves behind.\n ${chalk.blue.bold(\"--yes, -y\")} Skip prune's confirmation prompt. Dropping a\n branch is not undoable, so this is the flag\n a CI job passes and a person usually should not.\n\n${chalk.green.bold(\"Examples\")}\n ${chalk.gray(\"# Create a branch and work on it\")}\n rebase db branch create feature_auth\n rebase db branch switch feature_auth\n\n ${chalk.gray(\"# Create a branch from a specific source\")}\n rebase db branch create staging --from production\n\n ${chalk.gray(\"# Remove branches older than two weeks, and anything orphaned\")}\n rebase db branch prune --older-than 2w\n\n ${chalk.gray(\"# List all branches\")}\n rebase db branch list\n\n ${chalk.gray(\"# Delete a branch\")}\n rebase db branch delete feature_auth\n`);\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;\n}\n\n/** A branch's age, for \"…created 6d ago\". */\nfunction timeAgo(date: Date): string {\n // No horizon: a branch created a year ago should still report an age here,\n // rather than fall back to a bare date in a one-line list entry.\n return formatRelativeTime(date, { maxMs: Number.POSITIVE_INFINITY }) ?? \"unknown\";\n}\n\n\n\n/** Set when this process created the Atlas scratch database; see `ensureDevDatabaseExists`. */\nlet scratchDatabaseCreatedHere = false;\n\nasync function runAtlas(\n domain: \"schema\" | \"migrate\",\n args: string[],\n collectionsPath?: string,\n opts: { captureStdout?: boolean } = {}\n): Promise<string> {\n const atlasBin = resolveLocalBin(\"atlas\");\n if (!atlasBin) {\n // Two very different causes, and the advice for one is a loop for the\n // other — see `diagnoseMissingBin`. This used to say \"Install it with:\n // pnpm add -D @ariga/atlas\" unconditionally, which is the exact command\n // that produces the far more common of the two states.\n outError(chalk.red(\"\\n✗ The atlas binary is missing, so the schema cannot be applied.\\n\"));\n\n // Every remedy below is package-manager specific, and this used to print\n // pnpm's unconditionally. npm 12 blocks a dependency's install scripts\n // the same way pnpm 10 does, so an npm reader was handed `pnpm\n // approve-builds` and a `\"pnpm\"` package.json key — correct advice, for\n // somebody else. Read the lockfile and answer the reader in front of us.\n const manager = detectProjectPackageManager();\n\n const diagnosis = diagnoseMissingBin(\"@ariga/atlas\");\n\n if (diagnosis === \"bin-link-missing\") {\n // The binary IS on disk; only the `node_modules/.bin` shim that\n // points at it is not. pnpm produces this when it writes the link\n // before the script that creates the target (\"Failed to create bin\n // … ENOENT\"), and so does a tree copied without its symlinks.\n // Sending this reader to `approve-builds` does nothing: nothing is\n // blocked.\n outError(chalk.yellow(\" @ariga/atlas and its binary are both on disk — only the\\n\"\n + \" node_modules/.bin/atlas link that puts it on PATH is missing.\\n\"));\n outError(chalk.gray(\n \" Usually a half-written install: the link is created before the script that\\n\"\n + \" downloads the target, so an interrupted or copied tree keeps the binary and\\n\"\n + \" loses the shim.\\n\"\n ));\n outError(\" Fix it with:\\n\");\n outError(chalk.bold(` ${describeReinstallCommand(manager)}\\n`));\n } else if (diagnosis === \"build-script-blocked\") {\n outError(chalk.yellow(\" @ariga/atlas IS installed — only its binary is missing.\\n\"));\n outError(chalk.gray(\n \" It downloads that binary in a `preinstall` script, and pnpm 10+ and npm 12+\\n\" +\n \" do not run a dependency's scripts unless you allow it. The install still\\n\" +\n \" exits 0, so the only sign is a line several screens up: pnpm's\\n\" +\n \" `Ignored build scripts: @ariga/atlas`, or npm's `install scripts blocked`.\\n\"\n ));\n outError(\" Fix it with either:\\n\");\n for (const line of describeBuildScriptRemedy(\"@ariga/atlas\", manager)) {\n outError(line ? chalk.bold(line) : \"\");\n }\n outError(\"\");\n } else {\n outError(chalk.gray(\" It is not installed in this project.\\n\"));\n outError(\" Install it with:\\n\");\n outError(chalk.bold(` ${describeDevAddCommand(\"@ariga/atlas\", manager)}\\n`));\n outError(chalk.gray(\n \" If the install then reports blocked or ignored build scripts, allow them too —\\n\" +\n \" the package carries a `preinstall` script that fetches the binary.\\n\"\n ));\n }\n process.exit(1);\n }\n\n const env = { ...process.env as Record<string, string> };\n try {\n const dotenv = await import(\"dotenv\");\n const envPaths = [\n process.env.DOTENV_CONFIG_PATH,\n path.resolve(process.cwd(), \".env\"),\n path.resolve(process.cwd(), \"../.env\"),\n path.resolve(process.cwd(), \"../../.env\")\n ].filter(Boolean) as string[];\n\n for (const p of envPaths) {\n if (fs.existsSync(p)) {\n const parsed = dotenv.config({ path: p, quiet: true });\n if (parsed.parsed) {\n for (const [key, val] of Object.entries(parsed.parsed)) {\n if (env[key] === undefined) {\n env[key] = val;\n }\n }\n break;\n }\n }\n }\n } catch {\n // ignore\n }\n\n const databaseUrl = env.DATABASE_URL;\n if (!databaseUrl) {\n outError(chalk.red(\"✗ DATABASE_URL is not set. Make sure your .env file is configured.\"));\n process.exit(1);\n }\n\n // Pre-flight: verify the database is reachable before running Atlas.\n // This catches ECONNREFUSED / auth failures with a friendly banner\n // instead of letting Atlas surface a raw error.\n await checkDatabaseConnectivity(databaseUrl);\n\n const devDatabaseUrl = getDevDatabaseUrl(databaseUrl);\n // Remember whether the scratch database is ours: one a user created by\n // hand — the remedy for a role without CREATEDB — must survive the push,\n // or that user is back at the same refusal next time.\n if (await ensureDevDatabaseExists(databaseUrl, devDatabaseUrl)) scratchDatabaseCreatedHere = true;\n\n // Atlas speaks libpq, which rejects the `sslmode=no-verify` that\n // node-postgres accepts — see `forLibpq`. Rewritten only for the argv, so\n // everything above still connects with the URL as configured.\n const atlasUrl = forLibpq(databaseUrl);\n const atlasDevUrl = forLibpq(devDatabaseUrl);\n\n // Everything Atlas must keep its hands off, in one list.\n //\n // Gathered only for the invocations that accept the flag — which is\n // `schema apply` and nothing else. `atlas migrate diff` and `migrate apply`\n // both reject `--exclude` outright with `unknown flag`, and passing it there\n // took `rebase db generate` and `rebase db migrate` down for every project\n // declaring a `search` block; the diff keeps the same objects out of the\n // migration afterwards instead, with `stripCarvedOutStatements`. See\n // `acceptsExcludeFlag`.\n const excludes: string[] = [];\n if (collectionsPath && acceptsExcludeFlag(domain, args)) {\n // Search and vector objects are Rebase's, not Atlas's: the desired state\n // does not carry them, so an apply left to itself would drop them.\n excludes.push(...await getSearchExcludes(collectionsPath));\n excludes.push(...await getVectorExcludes(collectionsPath));\n excludes.push(...await getTriggerExcludes(collectionsPath));\n\n // Fail CLOSED: the exclude list is the only thing shielding\n // non-collection tables from the auto-approved apply. If we can't\n // introspect the database to build it, abort rather than proceed with\n // a partial list that would let Atlas drop unmanaged tables.\n try {\n excludes.push(...await getTableExcludes(databaseUrl, collectionsPath));\n } catch (err) {\n if (err instanceof ExcludeIntrospectionError) {\n outError(chalk.red(\"\\n✗ Aborting push: could not determine which tables to protect.\"));\n outError(chalk.gray(` ${err.message}`));\n outError(chalk.gray(\" Refusing to apply — a partial exclude list could drop tables Rebase does not manage.\"));\n const hint = diagnoseDbError(err.cause ?? err, databaseUrl);\n if (hint) outError(hint);\n process.exit(1);\n }\n throw err;\n }\n\n // And the indexes on those tables that Rebase did not create. Same\n // fail-closed contract as the table list above, for the same reason: a\n // partial answer here silently drops somebody's index.\n try {\n excludes.push(...await getForeignIndexExcludes(databaseUrl, collectionsPath));\n } catch (err) {\n if (err instanceof ExcludeIntrospectionError) {\n outError(chalk.red(\"\\n✗ Aborting push: could not determine which indexes to protect.\"));\n outError(chalk.gray(` ${err.message}`));\n outError(chalk.gray(\" Refusing to apply — a partial exclude list could drop an index Rebase does not manage.\"));\n const hint = diagnoseDbError(err.cause ?? err, databaseUrl);\n if (hint) outError(hint);\n process.exit(1);\n }\n throw err;\n }\n }\n\n const atlasArgs = buildAtlasArgs({ domain, args, url: atlasUrl, devUrl: atlasDevUrl, excludes });\n\n // Stream stdout live but tee stderr so we can inspect Atlas's error text\n // for known, actionable failure modes (e.g. a dependency-drop that leaves\n // the schema half-applied) after the process exits. When capturing (used\n // for the destructive-change dry-run), pipe stdout and collect it instead.\n const subprocess = execa(atlasBin, atlasArgs, {\n cwd: process.cwd(),\n stdout: opts.captureStdout ? \"pipe\" : \"inherit\",\n stderr: \"pipe\",\n env\n });\n let stdoutText = \"\";\n if (opts.captureStdout) {\n subprocess.stdout?.on(\"data\", (chunk: Buffer) => {\n stdoutText += chunk.toString();\n });\n }\n let stderrText = \"\";\n subprocess.stderr?.on(\"data\", (chunk: Buffer) => {\n const text = chunk.toString();\n stderrText += text;\n process.stderr.write(text);\n });\n try {\n await subprocess;\n } catch {\n outError(chalk.red(`\\n✗ atlas ${domain} ${args.join(\" \")} failed.\\n`));\n // Surface actionable recovery guidance for recognized failures. The\n // Atlas-shaped ones first: they read the invocation as well as the\n // text, so they can tell `migrate apply` hitting an already-provisioned\n // database (which wants a baseline) from `schema apply` hitting a real\n // conflict. `diagnoseDbError` is the connection-level fallback, shared\n // with the boot path.\n const atlasHint = await diagnoseAtlasFailure({\n domain,\n args,\n stderr: stderrText,\n databaseUrl,\n latestMigrationVersion: latestMigrationVersion()\n });\n const hint = atlasHint ?? diagnoseDbError({ message: stderrText }, databaseUrl);\n if (hint) {\n outError(hint);\n }\n process.exit(1);\n }\n // Atlas prints the plan to stdout, but fall back to stderr so the\n // destructive-change detector never misses a plan on a version/build that\n // routes it differently.\n if (opts.captureStdout) {\n return stdoutText.trim().length > 0 ? stdoutText : stderrText;\n }\n return \"\";\n}\n\nasync function generatePostgresDdlCommand(rawArgs: string[]): Promise<void> {\n const argsList = arg(\n {\n \"--collections\": String,\n \"--output\": String,\n \"-c\": \"--collections\",\n \"-o\": \"--output\"\n },\n {\n argv: rawArgs.slice(2),\n permissive: true\n }\n );\n\n const ddl = resolveChildScript(\"generate-postgres-ddl\");\n if (!ddl.ok) {\n outError(chalk.red(childScriptError(\"DDL generator\", ddl.reason)));\n process.exit(1);\n }\n\n const collectionsPath = argsList[\"--collections\"] || path.join(\"..\", \"config\", \"collections\");\n const outputPath = argsList[\"--output\"] || path.join(\"drizzle\", \"schema.sql\");\n\n const cmdParts = [\n ddl.bin,\n ddl.script,\n `--collections=${collectionsPath}`,\n `--output=${outputPath}`\n ];\n\n try {\n await execa(cmdParts[0], cmdParts.slice(1), {\n cwd: process.cwd(),\n stdio: \"inherit\",\n env: { ...process.env as Record<string, string> }\n });\n } catch (err: unknown) {\n // The generator runs with inherited stdio, so on a non-zero exit its\n // own message is already the last useful thing on the terminal and\n // execa's wrapper (\"Command failed with exit code 1: …/tsx …\") would\n // bury it. Repeat it only when the child never got as far as speaking.\n if (typeof (err as { exitCode?: number }).exitCode === \"number\") {\n outError(chalk.red(\"✗ Postgres DDL generation failed — nothing was applied.\"));\n } else {\n outError(chalk.red(`✗ Failed to run Postgres DDL generator: ${err instanceof Error ? err.message : String(err)}`));\n }\n process.exit(1);\n }\n}\n\n/**\n * `schema stale [--fix]` — is the generated Drizzle schema older than the rule\n * that derives its foreign-key names?\n *\n * This exists for one upgrade path and is worth the command. 0.13 derives\n * `category_id` where 0.12 derived `categorie_id`; boot-ensure renames the\n * database column to match, and the project's checked-in\n * `backend/src/schema.generated.ts` is then wrong in a way nothing the developer\n * did would explain. Relation validation refuses to boot on it, permanently,\n * because the rename has already been applied and will not run again.\n *\n * `rebase dev` calls this with `--fix` before starting the backend, so the\n * upgrade behaves the way the release note says it does: the column moves and the\n * project keeps working. Without `--fix` it reports and exits non-zero, which is\n * what a build or a CI step wants.\n */\nasync function schemaStaleCommand(rawArgs: string[]): Promise<void> {\n const argsList = arg(\n {\n \"--collections\": String,\n \"--output\": String,\n \"--fix\": Boolean,\n \"-c\": \"--collections\",\n \"-o\": \"--output\",\n // Both spellings, on every command that writes a file. See\n // `OUTPUT_FLAG_ALIASES` in cli-flags.ts.\n \"--out\": \"--output\"\n },\n { argv: rawArgs.slice(2), permissive: true }\n );\n\n const collectionsPath = argsList[\"--collections\"] || path.join(\"..\", \"config\", \"collections\");\n const outputPath = argsList[\"--output\"] || path.join(\"src\", \"schema.generated.ts\");\n const schemaFile = path.resolve(process.cwd(), outputPath);\n\n const fix = Boolean(argsList[\"--fix\"]);\n const generatedExists = fs.existsSync(schemaFile);\n\n const { loadCollections } = await import(\"./schema/doctor\");\n const { findLegacyForeignKeyNames, staleVerdict } =\n await import(\"./schema/generated-schema-staleness\");\n\n let stale: ReturnType<typeof findLegacyForeignKeyNames> = [];\n let unreadable: string | undefined;\n if (generatedExists) {\n try {\n const collections = await loadCollections(path.resolve(process.cwd(), collectionsPath));\n stale = findLegacyForeignKeyNames(fs.readFileSync(schemaFile, \"utf8\"), collections);\n } catch (err) {\n // Best-effort by design: a collections directory that will not load\n // is a real error, but it is one the boot reports far better than\n // this does. Said out loud all the same — this command used to exit\n // 0 in silence here, which is indistinguishable from a clean run.\n unreadable = err instanceof Error ? err.message : String(err);\n logger.debug(`schema stale: skipped (${unreadable})`);\n }\n }\n\n // The decision lives in `generated-schema-staleness.ts` so it can be tested:\n // this file uses `import.meta`, which the driver's jest suite cannot load,\n // and three of this command's four paths were silent because of it.\n const verdict = staleVerdict({ outputPath, generatedExists, stale, unreadable, fix });\n\n for (const line of verdict.lines) {\n if (!line) out(\"\");\n else if (line.includes(\"⚠️\")) outWarn(chalk.yellow(line));\n else if (verdict.exitCode !== 0) outError(chalk.red(line));\n else if (line.includes(\"✓\")) out(chalk.green(line));\n else out(chalk.gray(line));\n }\n\n if (verdict.exitCode !== 0) process.exit(verdict.exitCode);\n if (!verdict.regenerate) return;\n\n await schemaCommand(\"generate\", [\"schema\", \"generate\", `--collections=${collectionsPath}`, `--output=${outputPath}`]);\n}\n\nasync function schemaCommand(subcommand: string, rawArgs: string[]): Promise<void> {\n // The same second line of defence `dbCommand` above carries, for the same\n // reason: this file is also its own CLI, spawned directly by\n // `resolvePluginCliScript` and executable on its own. Nothing here had a\n // `--help` case, so `schema generate --help` regenerated the schema and\n // `schema introspect --help` rewrote the collection files — a flag whose\n // entire job is to print text, overwriting authored source.\n //\n // Guarded by a real subcommand: the internal callers below re-enter this\n // function with a synthesised argv, and none of them can carry `--help`.\n if (subcommand && (rawArgs.includes(\"--help\") || rawArgs.includes(\"-h\"))) {\n out(\"\");\n out(chalk.bold(` rebase schema ${subcommand}`));\n out(chalk.gray(\" Run `rebase schema --help` for the full page — this is the driver's own entry point.\"));\n out(\"\");\n return;\n }\n\n if (subcommand === \"stale\") {\n await schemaStaleCommand(rawArgs);\n return;\n }\n\n if (subcommand === \"generate\") {\n const argsList = arg(\n {\n \"--collections\": String,\n \"--output\": String,\n \"--watch\": Boolean,\n \"-c\": \"--collections\",\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"-w\": \"--watch\"\n },\n {\n argv: rawArgs.slice(2), // db generate ... or schema generate ...\n permissive: true\n }\n );\n\n // Here we just invoke the local generate-drizzle-schema.ts since we are inside the postgresql-backend\n // If installed in node_modules, __cliDirname is node_modules/@rebasepro/server-postgres/dist or src.\n const generator = resolveChildScript(\"generate-drizzle-schema\");\n if (!generator.ok) {\n outError(chalk.red(childScriptError(\"schema generator\", generator.reason)));\n process.exit(1);\n }\n\n const collectionsPath = argsList[\"--collections\"] || path.join(\"..\", \"config\", \"collections\");\n const outputPath = argsList[\"--output\"] || path.join(\"src\", \"schema.generated.ts\");\n const watch = argsList[\"--watch\"] || false;\n\n out(\"\");\n out(chalk.bold(\" 🔧 Rebase Schema Generator\"));\n out(\"\");\n\n const cmdParts = [\n generator.bin,\n generator.script,\n `--collections=${collectionsPath}`,\n `--output=${outputPath}`\n ];\n if (watch) {\n cmdParts.push(\"--watch\");\n }\n\n try {\n await execa(cmdParts[0], cmdParts.slice(1), {\n cwd: process.cwd(),\n stdio: \"inherit\",\n env: { ...process.env as Record<string, string> }\n });\n } catch (err: unknown) {\n // Same contract as the DDL generator above: a child that exited\n // non-zero has already printed the cause on inherited stdio.\n if (typeof (err as { exitCode?: number }).exitCode === \"number\") {\n outError(chalk.red(\"✗ Drizzle schema generation failed — nothing was applied.\"));\n } else {\n outError(chalk.red(`✗ Failed to run schema generator: ${err instanceof Error ? err.message : String(err)}`));\n }\n process.exit(1);\n }\n } else if (subcommand === \"introspect\") {\n const argsList = arg(\n {\n \"--output\": String,\n \"--collections\": String,\n \"--force\": Boolean,\n \"--schema\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"-c\": \"--collections\",\n \"-f\": \"--force\"\n },\n {\n argv: rawArgs.slice(2),\n permissive: true\n }\n );\n\n const introspect = resolveChildScript(\"introspect-db\");\n if (!introspect.ok) {\n outError(chalk.red(childScriptError(\"introspection script\", introspect.reason)));\n process.exit(1);\n }\n\n const outputPath = argsList[\"--output\"] || argsList[\"--collections\"] || path.join(\"..\", \"config\", \"collections\");\n\n out(\"\");\n out(chalk.bold(\" 🔍 Rebase Schema Introspector\"));\n out(\"\");\n\n const cmdParts = [\n introspect.bin,\n introspect.script,\n `--output=${outputPath}`,\n ...(argsList[\"--force\"] ? [\"--force\"] : []),\n ...(argsList[\"--schema\"] ? [`--schema=${argsList[\"--schema\"]}`] : [])\n ];\n\n try {\n await execa(cmdParts[0], cmdParts.slice(1), {\n cwd: process.cwd(),\n stdio: \"inherit\",\n env: { ...process.env as Record<string, string> }\n });\n } catch (err: unknown) {\n outError(chalk.red(`✗ Failed to run schema introspector: ${err instanceof Error ? err.message : String(err)}`));\n process.exit(1);\n }\n } else {\n outError(chalk.red(\"Unknown schema command.\"));\n process.exit(1);\n }\n}\n\nasync function doctorPluginCommand(rawArgs: string[]): Promise<void> {\n const parsedArgs = arg(\n {\n \"--collections\": String,\n \"--schema\": String,\n \"--sdk\": String,\n \"--policies\": Boolean,\n \"-c\": \"--collections\",\n \"-s\": \"--schema\",\n \"-k\": \"--sdk\"\n },\n {\n argv: rawArgs.slice(1), // skip \"doctor\"\n permissive: true\n }\n );\n\n const doctor = resolveChildScript(\"doctor-cli\");\n if (!doctor.ok) {\n outError(chalk.red(childScriptError(\"doctor script\", doctor.reason)));\n process.exit(1);\n }\n\n const collectionsPath = parsedArgs[\"--collections\"] || path.join(\"..\", \"config\", \"collections\");\n const schemaPath = parsedArgs[\"--schema\"] || path.join(\"src\", \"schema.generated.ts\");\n const sdkPath = parsedArgs[\"--sdk\"] || path.join(\"..\", \"generated\", \"sdk\", \"database.types.ts\");\n\n const cmdParts = [\n doctor.bin,\n doctor.script,\n `--collections=${collectionsPath}`,\n `--schema=${schemaPath}`,\n `--sdk=${sdkPath}`,\n // Only the RLS checks: skips the schema/SDK diff, so it can run against\n // a deployed database as a CI gate.\n ...(parsedArgs[\"--policies\"] ? [\"--policies\"] : [])\n ];\n\n try {\n await execa(cmdParts[0], cmdParts.slice(1), {\n cwd: process.cwd(),\n stdio: \"inherit\",\n env: { ...process.env as Record<string, string> }\n });\n } catch {\n process.exit(1);\n }\n}\n\n\n// Entry point when called directly\nconst argv1Real = process.argv[1] ? fs.realpathSync(process.argv[1]) : \"\";\nif (import.meta.url === `file://${argv1Real}`) {\n // Drop node and script path\n runPluginCommand(process.argv.slice(2)).catch((error: unknown) => {\n reportCommandFailure(error);\n process.exit(1);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,IAAM,uBAAwD;CAC1D;EAAE,OAAO;EAAc,IAAI;CAAoB;CAC/C;EAAE,OAAO;EAAe,IAAI;CAAqB;CACjD;EAAE,OAAO;EAAe,IAAI;CAAqB;CACjD;EAAE,OAAO;EAAa,IAAI;CAAqC;CAC/D;EAAE,OAAO;EAAa,IAAI;CAAmB;CAC7C;EAAE,OAAO;EAAY,IAAI;CAAgB;AAC7C;;;;;;;AAQA,SAAgB,mBAAmB,KAAuB;CAOtD,OAJwB,IACnB,MAAM,IAAI,CAAC,CACX,QAAQ,SAAS,CAAC,KAAK,KAAK,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAC/C,KAAK,IACH,CAAA,CACF,MAAM,GAAG,CAAC,CACV,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC,CACpB,QAAQ,MAAM,EAAE,SAAS,CAAC;AACnC;;;;;;AAcA,SAAgB,4BAA4B,SAAyC;CACjF,MAAM,QAAgC,CAAC;CACvC,KAAK,MAAM,aAAa,mBAAmB,OAAO,GAC9C,KAAK,MAAM,EAAE,OAAO,QAAQ,sBACxB,IAAI,GAAG,KAAK,SAAS,GAAG;EACpB,MAAM,KAAK;GAAE;GAAW,MAAM;EAAM,CAAC;EACrC;CACJ;CAGR,OAAO;AACX;;;;;;;;;;;AAcA,SAAgB,iBAAiB,MAIhB;CACb,IAAI,KAAK,qBAAqB,GAAG,OAAO;CACxC,IAAI,KAAK,kBAAkB,OAAO;CAClC,OAAO,KAAK,cAAc,YAAY;AAC1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7BA,IAAM,UAAQ,OAAO,GAAG;AACxB,IAAM,WAAW,IAAI,OAAO,OAAO,GAAG,iCAAiC,QAAM,SAAS,QAAM,MAAM,GAAG;AACrG,IAAM,kBAAkB,IAAI,OACxB,OAAO,GAAG,4BAA4B,QAAM,+BAA+B,IAC/E;AACA,IAAM,mBAAiB,IAAI,OACvB,OAAO,GAAG,yCAAyC,QAAM,IAAI,IACjE;AAEA,IAAM,WAAW,UACb,MAAM,WAAW,IAAI,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI;;;;;;;;;;AAWlD,IAAM,mBAAmB,cACrB,UAAU,QAAQ,aAAa,EAAE,CAAC,CAAC,KAAK;;;;;;;;AAS5C,SAAgB,qBAAqB,SAAmC;CACpE,MAAM,YAA8B,CAAC;CAErC,KAAK,MAAM,OAAO,mBAAmB,OAAO,GAAG;EAC3C,MAAM,YAAY,gBAAgB,GAAG;EACrC,MAAM,QAAQ,SAAS,KAAK,SAAS;EACrC,IAAI,CAAC,OAAO;EAKZ,MAAM,CAAC,QAAQ,QAAQ,MAAM,KACvB,CAAC,QAAQ,MAAM,EAAE,GAAG,QAAQ,MAAM,EAAE,CAAC,IACrC,CAAC,KAAA,GAAW,QAAQ,MAAM,EAAE,CAAC;EAEnC,MAAM,WAAW,IAAY,SAA6B;GACtD,GAAG,YAAY;GACf,IAAI;GACJ,QAAQ,QAAQ,GAAG,KAAK,SAAS,OAAO,MACpC,UAAU,KAAK;IAAE;IAAQ,OAAO;IAAM,QAAQ,QAAQ,MAAM,EAAE;IAAG;GAAK,CAAC;EAE/E;EACA,QAAQ,iBAAiB,MAAM;EAC/B,QAAQ,kBAAgB,MAAM;CAClC;CAEA,OAAO;AACX;;;;;;;;;;;AAYA,SAAgB,6BACZ,WACA,cACyB;CACzB,MAAM,4BAAY,IAAI,IAAqC;CAE3D,KAAK,MAAM,cAAc,cACrB,KAAK,MAAM,YAAY,WAAW;EAC9B,IAAI,SAAS,UAAU,WAAW,OAAO;EACzC,IAAI,SAAS,WAAW,KAAA,KAAa,SAAS,WAAW,WAAW,QAAQ;EAC5E,IAAI,SAAS,WAAW,WAAW,WAAW;EAE9C,MAAM,MAAM,GAAG,WAAW,OAAO,GAAG,WAAW,MAAM,GAAG,WAAW;EACnE,MAAM,WAAW,UAAU,IAAI,GAAG,KAAK;GACnC,QAAQ,WAAW;GACnB,OAAO,WAAW;GAClB,QAAQ,WAAW;GACnB,UAAU,CAAC;EACf;EACA,IAAI,CAAC,SAAS,SAAS,MAAK,MAAK,EAAE,WAAW,SAAS,UAAU,EAAE,SAAS,SAAS,IAAI,GACrF,SAAS,SAAS,KAAK;GAAE,QAAQ,SAAS;GAAQ,MAAM,SAAS;EAAK,CAAC;EAE3E,UAAU,IAAI,KAAK,QAAQ;CAC/B;CAGJ,MAAM,UAAU,CAAC,GAAG,UAAU,OAAO,CAAC;CACtC,KAAK,MAAM,YAAY,SAAS,SAAS,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,cAAc,EAAE,MAAM,CAAC;CACjG,OAAO,QAAQ,MAAM,GAAG,MAAM,GAAG,EAAE,OAAO,GAAG,EAAE,MAAM,GAAG,EAAE,SAAS,cAAc,GAAG,EAAE,OAAO,GAAG,EAAE,MAAM,GAAG,EAAE,QAAQ,CAAC;AAC1H;;;;;;;;;;AAWA,SAAgB,qBACZ,WACA,iBAC0E;CAC1E,MAAM,QAAQ,IAAI,IAAI,eAAe;CACrC,MAAM,UAAqC,CAAC;CAC5C,MAAM,UAAqC,CAAC;CAC5C,KAAK,MAAM,YAAY,WAAW;EAC9B,MAAM,SAAS,GAAG,SAAS,OAAO,GAAG,SAAS,MAAM,GAAG,SAAS;EAChE,CAAC,MAAM,IAAI,MAAM,IAAI,UAAU,QAAA,CAAS,KAAK,QAAQ;CACzD;CACA,OAAO;EAAE;EAAS;CAAQ;AAC9B;;;;;;;;;AAUA,SAAgB,8BACZ,WACA,OAA+B,CAAC,GACxB;CACR,MAAM,QAAQ,KAAK,WAAW,eAAe;CAC7C,OAAO,UAAU,KAAI,MAAK,gBAAgB,EAAE,OAAO,KAAK,EAAE,MAAM,gBAAgB,MAAM,GAAG,EAAE,OAAO,GAAG;AACzG;;;;;;;;;AAUA,SAAgB,sBAAsB,WAA8C;CAChF,IAAI,UAAU,WAAW,GAAG,OAAO;CAKnC,OAAO;EACH;EACA;EACA;EACA,GARY,UAAU,KAAI,MAAK;GAC/B,MAAM,QAAQ,EAAE,SAAS,KAAI,MAAK,GAAG,EAAE,OAAO,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI;GACtE,OAAO,QAAQ,iBAAiB,CAAC,EAAE,SAAS;EAChD,CAKO;EACH;EACA,GAAG,8BAA8B,WAAW,EAAE,UAAU,KAAK,CAAC;EAC9D;CACJ,CAAC,CAAC,KAAK,IAAI;AACf;;AAGA,SAAgB,iBAAiB,UAA2C;CACxE,OAAO,GAAG,SAAS,OAAO,GAAG,SAAS,MAAM,GAAG,SAAS;AAC5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvMA,IAAM,QAAQ;AACd,IAAM,YAAY,GAAG,MAAM,gBAAgB,MAAM;AAEjD,IAAM,iBAAiB,IAAI,OAAO,oCAAoC,UAAU,oBAAoB,GAAG;AACvG,IAAM,iBAAiB,IAAI,OAAO,iDAAiD,MAAM,KAAK,GAAG;AACjG,IAAM,gBAAgB,IAAI,OAAO,gEAAgE,UAAU,KAAK,GAAG;;;;;;;;AASnH,IAAM,gBAAgB;;;;;;;AA6BtB,SAAgB,qBAAqB,UAAuC;CACxE,MAAM,SAA4B,CAAC;CACnC,KAAK,MAAM,WAAW,UAAU;EAC5B,MAAM,QAAQ,QAAQ,MAAM,GAAG;EAC/B,IAAI,MAAM,WAAW,GAAG;EACxB,IAAI,MAAM,MAAM,MAAM,EAAE,WAAW,CAAC,GAAG;EACvC,OAAO,KAAK;GAAE,QAAQ,MAAM;GAAI,OAAO,MAAM;GAAI,QAAQ,MAAM;EAAG,CAAC;CACvE;CACA,OAAO;AACX;;AAGA,SAAS,kBAAkB,KAAqB;CAC5C,MAAM,UAAU,IAAI,KAAK;CACzB,IAAI,QAAQ,WAAW,IAAI,KAAK,QAAQ,SAAS,IAAI,KAAK,QAAQ,UAAU,GACxE,OAAO,QAAQ,MAAM,GAAG,EAAE,CAAC,CAAC,QAAQ,OAAO,IAAI;CAGnD,OAAO,QAAQ,YAAY;AAC/B;;AAGA,SAAS,mBAAmB,KAA8B;CACtD,MAAM,QAAkB,CAAC;CACzB,IAAI,UAAU;CACd,IAAI,UAAU;CACd,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;EACjC,MAAM,KAAK,IAAI;EACf,IAAI,SAAS;GACT,IAAI,OAAO,MAAM;IACb,IAAI,IAAI,IAAI,OAAO,MAAM;KAAE,WAAW;KAAQ;KAAK;IAAU;IAC7D,UAAU;GACd;GACA,WAAW;GACX;EACJ;EACA,IAAI,OAAO,MAAM;GAAE,UAAU;GAAM,WAAW;GAAI;EAAU;EAC5D,IAAI,OAAO,KAAK;GAAE,MAAM,KAAK,OAAO;GAAG,UAAU;GAAI;EAAU;EAC/D,WAAW;CACf;CACA,IAAI,SAAS,OAAO;CACpB,MAAM,KAAK,OAAO;CAClB,OAAO,MAAM,IAAI,iBAAiB;AACtC;;;;;;;;;;;AA4BA,SAAS,iBAAiB,KAAwC;CAC9D,MAAM,aAAiC,CAAC;CACxC,IAAI,IAAI;CACR,IAAI,iBAAiB;CACrB,IAAI,UAAU;CAEd,MAAM,iBAAiB,iBAAyB;EAC5C,MAAM,UAAU,IAAI,MAAM,gBAAgB,YAAY;EAEtD,IAAI,WAAW;EACf,KAAK,MAAM,QAAQ,QAAQ,MAAM,IAAI,GAAG;GACpC,MAAM,UAAU,KAAK,KAAK;GAC1B,IAAI,YAAY,MAAM,QAAQ,WAAW,IAAI,GAAG;IAC5C,YAAY,KAAK,SAAS;IAC1B;GACJ;GACA;EACJ;EACA,MAAM,YAAY,iBAAiB;EACnC,WAAW,KAAK;GACZ,OAAO;GACP,KAAK;GACL;GACA,MAAM,IAAI,MAAM,WAAW,YAAY,CAAC,CAAC,QAAQ,SAAS,EAAE,CAAC,CAAC,KAAK;EACvE,CAAC;CACL;CAEA,OAAO,IAAI,IAAI,QAAQ;EACnB,MAAM,KAAK,IAAI;EAEf,IAAI,OAAO,OAAO,IAAI,IAAI,OAAO,KAAK;GAClC,MAAM,KAAK,IAAI,QAAQ,MAAM,CAAC;GAC9B,IAAI,OAAO,KAAK,IAAI,SAAS,KAAK;GAClC;EACJ;EACA,IAAI,OAAO,OAAO,IAAI,IAAI,OAAO,KAAK;GAClC,MAAM,QAAQ,IAAI,QAAQ,MAAM,IAAI,CAAC;GACrC,IAAI,UAAU,IAAI,OAAO;GACzB,IAAI,QAAQ;GACZ,UAAU;GACV;EACJ;EACA,IAAI,OAAO,OAAO,OAAO,MAAM;GAC3B,MAAM,QAAQ;GACd;GACA,IAAI,SAAS;GACb,OAAO,IAAI,IAAI,QAAQ;IACnB,IAAI,IAAI,OAAO,OAAO;KAClB,IAAI,IAAI,IAAI,OAAO,OAAO;MAAE,KAAK;MAAG;KAAU;KAC9C;KACA,SAAS;KACT;IACJ;IACA;GACJ;GACA,IAAI,CAAC,QAAQ,OAAO;GACpB,UAAU;GACV;EACJ;EACA,IAAI,OAAO,KAAK;GACZ,MAAM,MAAM,qDAAqD,KAAK,IAAI,MAAM,CAAC,CAAC;GAClF,IAAI,KAAK;IACL,MAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC,MAAM;IACnD,IAAI,UAAU,IAAI,OAAO;IACzB,IAAI,QAAQ,IAAI,EAAE,CAAC;IACnB,UAAU;IACV;GACJ;EACJ;EACA,IAAI,OAAO,KAAK;GACZ,cAAc,IAAI,CAAC;GACnB;GACA,iBAAiB;GACjB,UAAU;GACV;EACJ;EACA,IAAI,CAAC,KAAK,KAAK,EAAE,GAAG,UAAU;EAC9B;CACJ;CAGA,IAAI,SAAS,OAAO;CACpB,OAAO;AACX;;AAGA,SAAS,aAAa,SAAkC;CACpD,MAAM,UAAoB,CAAC;CAC3B,IAAI,QAAQ;CACZ,IAAI,UAAU;CACd,IAAI,IAAI;CACR,OAAO,IAAI,QAAQ,QAAQ;EACvB,MAAM,KAAK,QAAQ;EACnB,IAAI,OAAO,OAAO,OAAO,MAAM;GAC3B,MAAM,QAAQ;GACd,WAAW;GACX;GACA,IAAI,SAAS;GACb,OAAO,IAAI,QAAQ,QAAQ;IACvB,WAAW,QAAQ;IACnB,IAAI,QAAQ,OAAO,OAAO;KACtB,IAAI,QAAQ,IAAI,OAAO,OAAO;MAAE,WAAW,QAAQ,IAAI;MAAI,KAAK;MAAG;KAAU;KAC7E;KACA,SAAS;KACT;IACJ;IACA;GACJ;GACA,IAAI,CAAC,QAAQ,OAAO;GACpB;EACJ;EACA,IAAI,OAAO,KAAK;GAAE;GAAS,WAAW;GAAI;GAAK;EAAU;EACzD,IAAI,OAAO,KAAK;GAAE;GAAS,WAAW;GAAI;GAAK;EAAU;EACzD,IAAI,OAAO,OAAO,UAAU,GAAG;GAAE,QAAQ,KAAK,OAAO;GAAG,UAAU;GAAI;GAAK;EAAU;EACrF,WAAW;EACX;CACJ;CACA,IAAI,UAAU,GAAG,OAAO;CACxB,QAAQ,KAAK,OAAO;CACpB,OAAO,QAAQ,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,MAAM,EAAE,SAAS,CAAC;AAClE;;;;;;;;AASA,SAAgB,yBAAyB,cAAsB,UAAiC;CAC5F,MAAM,SAAS,qBAAqB,QAAQ;CAC5C,IAAI,OAAO,WAAW,GAClB,OAAO;EAAE,KAAK;EAAc,SAAS,CAAC;EAAG,WAAW,CAAC;EAAG,OAAO,QAAQ,YAAY;CAAE;CAGzF,MAAM,UAAU,iBAAiB,YAAY;CAC7C,IAAI,YAAY,MAMZ,OAAO;EACH,KAAK;EACL,SAAS,CAAC;EACV,WALY,cAAc,KAAK,YAAY,KACxC,OAAO,MAAM,MAAM,aAAa,SAAS,EAAE,MAAM,CAAC,IAIhC,CAAC,aAAa,KAAK,CAAC,IAAI,CAAC;EAC9C,OAAO,QAAQ,YAAY;CAC/B;CAGJ,MAAM,UAAoB,CAAC;CAC3B,MAAM,YAAsB,CAAC;CAG7B,MAAM,QAA+D,CAAC;CAEtE,KAAK,MAAM,aAAa,SAAS;EAC7B,IAAI,CAAC,OAAO,MAAM,MAAM,UAAU,KAAK,SAAS,EAAE,MAAM,CAAC,GAAG;EAE5D,MAAM,YAAY,cAAc,KAAK,UAAU,IAAI;EACnD,IAAI,WAAW;GACX,MAAM,QAAQ,mBAAmB,UAAU,EAAE;GAC7C,MAAM,OAAO,QAAQ,MAAM,SAAS;GACpC,MAAM,SAAS,SAAS,MAAM,SAAS,IAAI,MAAM,MAAM,SAAS,KAAK,KAAA;GACrE,IAAI,SAAS,KAAA,KAAa,OAAO,MAAM,MACnC,EAAE,WAAW,SAAS,WAAW,KAAA,KAAa,EAAE,WAAW,OAAO,GAAG;IACrE,QAAQ,KAAK,UAAU,IAAI;IAC3B,MAAM,KAAK;KAAE,OAAO,UAAU;KAAO,KAAK,UAAU;KAAK,aAAa;IAAG,CAAC;GAC9E,OAII,UAAU,KAAK,UAAU,IAAI;GAEjC;EACJ;EAIA,MAAM,QAAQ,eAAe,KAAK,UAAU,IAAI;EAChD,IAAI,CAAC,OAAO;GACR,IAAI,cAAc,KAAK,UAAU,IAAI,GAAG,UAAU,KAAK,UAAU,IAAI;GACrE;EACJ;EAEA,MAAM,SAAS,mBAAmB,MAAM,EAAE;EAC1C,IAAI,CAAC,QAAQ;GACT,IAAI,cAAc,KAAK,UAAU,IAAI,GAAG,UAAU,KAAK,UAAU,IAAI;GACrE;EACJ;EACA,MAAM,QAAQ,OAAO,OAAO,SAAS;EACrC,MAAM,SAAS,OAAO,SAAS,IAAI,OAAO,OAAO,SAAS,KAAK,KAAA;EAE/D,MAAM,UAAU,aAAa,MAAM,EAAE;EACrC,IAAI,CAAC,SAAS;GACV,IAAI,cAAc,KAAK,UAAU,IAAI,GAAG,UAAU,KAAK,UAAU,IAAI;GACrE;EACJ;EAEA,MAAM,YAAsB,CAAC;EAC7B,IAAI,cAAc;EAClB,IAAI,gBAAgB;EACpB,KAAK,MAAM,UAAU,SAAS;GAC1B,MAAM,OAAO,eAAe,KAAK,MAAM;GACvC,MAAM,SAAS,OAAO,kBAAkB,KAAK,EAAE,IAAI,KAAA;GAKnD,IAJiB,WAAW,KAAA,KAAa,OAAO,MAAM,MAClD,EAAE,WAAW,UACb,EAAE,UAAU,UACX,WAAW,KAAA,KAAa,EAAE,WAAW,OAAO,GACnC;IACV,QAAQ,KAAK,eAAe,MAAM,GAAG,IAAI,QAAQ;IACjD;IACA;GACJ;GAGA,IAAI,cAAc,KAAK,MAAM,KAAK,OAAO,MAAM,MAAM,OAAO,SAAS,EAAE,MAAM,CAAC,GAC1E,gBAAgB;GAEpB,UAAU,KAAK,MAAM;EACzB;EAEA,IAAI,eAAe,UAAU,KAAK,UAAU,IAAI;EAChD,IAAI,gBAAgB,GAAG;EAEvB,IAAI,UAAU,WAAW,GACrB,MAAM,KAAK;GAAE,OAAO,UAAU;GAAO,KAAK,UAAU;GAAK,aAAa;EAAG,CAAC;OAE1E,MAAM,KAAK;GACP,OAAO,UAAU;GACjB,KAAK,UAAU;GACf,aAAa,eAAe,MAAM,GAAG,GAAG,UAAU,KAAK,IAAI,EAAE;EACjE,CAAC;CAET;CAEA,IAAI,MAAM;CACV,KAAK,MAAM,QAAQ,MAAM,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,GACrD,MAAM,IAAI,MAAM,GAAG,KAAK,KAAK,IAAI,KAAK,cAAc,IAAI,MAAM,KAAK,GAAG;CAE1E,IAAI,MAAM,SAAS,GAAG,MAAM,KAAK,GAAG;CAEpC,OAAO;EAAE;EAAK;EAAS;EAAW,OAAO,QAAQ,GAAG;CAAE;AAC1D;;AAGA,SAAS,QAAQ,KAAsB;CACnC,OAAO,IACF,MAAM,IAAI,CAAC,CACX,OAAO,SAAS,KAAK,KAAK,MAAM,MAAM,KAAK,KAAK,CAAC,CAAC,WAAW,IAAI,CAAC;AAC3E;;AAGA,SAAS,KAAK,KAAqB;CAC/B,MAAM,UAAU,IAAI,QAAQ,WAAW,MAAM,CAAC,CAAC,QAAQ,UAAU,EAAE,CAAC,CAAC,QAAQ;CAC7E,OAAO,QAAQ,WAAW,IAAI,KAAK,GAAG,QAAQ;AAClD;;;;;;;;;;;;;;;;;;;;AC1VA,SAAgB,mBAAmB,QAAgB,MAAyB;CACxE,OAAO,WAAW,YAAY,KAAK,SAAS,OAAO;AACvD;;AAGA,SAAgB,eAAe,YAAuC;CAClE,MAAM,EAAE,QAAQ,MAAM,KAAK,QAAQ,WAAW,CAAC,MAAM;CACrD,MAAM,OAAO,CAAC,QAAQ,GAAG,IAAI;CAE7B,IAAI,WAAW;MACP,KAAK,SAAS,OAAO,GACrB,KAAK,KAAK,SAAS,KAAK,aAAa,MAAM;OACxC,IAAI,KAAK,SAAS,OAAO,KAAK,KAAK,SAAS,SAAS,GACxD,KAAK,KAAK,SAAS,GAAG;CAAA,OAEvB,IAAI,WAAW;MACd,KAAK,SAAS,MAAM,GACpB,KAAK,KAAK,aAAa,MAAM;OAC1B,IAAI,KAAK,SAAS,OAAO,KAAK,KAAK,SAAS,QAAQ,GAAG;GAC1D,KAAK,KAAK,SAAS,KAAK,sBAAsB,QAAQ;GAKtD,IAAI,KAAK,SAAS,OAAO,KAAK,CAAC,KAAK,SAAS,YAAY,GACrD,KAAK,KAAK,eAAe;EAEjC;;CAMJ,IAAI,mBAAmB,QAAQ,IAAI,GAC/B,KAAK,MAAM,WAAW,UAClB,KAAK,KAAK,aAAa,OAAO;CAItC,OAAO;AACX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrEA,SAAgB,qBAAqB,OAAoC;CACrE,MAAM,SAAmB,CAAC;CAO1B,IAAI,WAAW;CACf,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;EAClD,MAAM,OAAO,MAAM;EACnB,IAAI,KAAK,WAAW,GAAG,GAAG;GACtB,IAAI,cAAc,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC,EAAE,GAAG,SAAS;GACpD;EACJ;EACA,IAAI,CAAC,UAAU;GACX,WAAW;GACX;EACJ;EACA,OAAO,KAAK,IAAI;CACpB;CAEA,OAAO;AACX;;;;;;;;;;AAWA,IAAM,gCAAgB,IAAI,IAAI;CAAC;CAAU;CAAgB;AAAgB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3B1E,IAAM,gBAA0B;CAC5B,kBAAkB;CAClB,YAAY;CACZ,WAAW;CACX,UAAU;CACV,MAAM;AACV;;AAGA,IAAa,oBAA8C;CACvD,WAAW;EACP,iBAAiB;EACjB,MAAM;EACN,aAAa;EACb,uBAAuB;EACvB,SAAS;EACT,MAAM;CACV;CACA,eAAe;EACX,iBAAiB;EACjB,MAAM;CACV;CAUA,cAAc,EACV,cAAc,OAClB;CACA,mBAAmB;EACf,iBAAiB;EACjB,MAAM;EACN,YAAY;EACZ,MAAM;EACN,SAAS;EACT,WAAW;EACX,MAAM;CACV;CACA,qBAAqB;EACjB,YAAY;EACZ,MAAM;EACN,SAAS;EACT,iBAAiB;EACjB,MAAM;EACN,WAAW;EACX,MAAM;EACN,YAAY;CAChB;CACA,gBAAgB;EACZ,iBAAiB;EACjB,MAAM;EACN,YAAY;EACZ,MAAM;EACN,SAAS;EACT,SAAS;CACb;AACJ;;;;;;;;;;;;;AA4CA,SAAgB,kBAAkB,MAA+B;CAC7D,IAAI;EAMA,QAAA,GAAA,WAAA,QAAA,CAJI;GAAE,iBAAiB;GAAQ,MAAM;EAAgB,GACjD;GAAE,MAAM,KAAK,MAAM,CAAC;GAAG,YAAY;EAAK,CAGrC,CAAA,CAAO,oBAAoB;CACtC,QAAQ;EACJ,OAAO;CACX;AACJ;;;;;;;;;;;AA2EA,SAAgB,iBAAiB,QAAgB,YAAgC,MAAsB;CACnG,IAAI,CAAC,YAAY;CACjB,MAAM,OAAO,kBAAkB,GAAG,OAAO,GAAG;CAC5C,IAAI,CAAC,MAAM;CAEX,IAAI;EACA,CAAA,GAAA,WAAA,QAAA,CAAI;GAAE,GAAG;GAAe,GAAG;EAAK,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;CAC9D,SAAS,KAAK;EACV,IAAI,eAAe,SAAU,IAAqB,SAAS,sBACvD,MAAM,IAAI,MACN,GAAG,IAAI,QAAQ,kBAAkB,OAAO,8BACnC,OAAO,GAAG,WAAW,UAC9B;EAEJ,MAAM;CACV;AACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnNA,IAAa,yBAAb,cAA4C,MAAM;CAGzB;CAAwB;CAF7C,kBAA2B;CAE3B,YAAY,OAAwB,UAA2B;EAC3D,MAAM,gCAAgC,MAAM,EAAE;EAD7B,KAAA,QAAA;EAAwB,KAAA,WAAA;EAEzC,KAAK,OAAO;CAChB;AACJ;;;;;;;;;AAUA,SAAgB,+BAA+B,OAAe,UAA0B;CACpF,OAAO;EACH,MAAM,IAAI,kCAAkC,MAAM,EAAE;EACpD,MAAM,KAAK,oBAAoB,UAAU;EACzC,MAAM,KAAK,yBAAyB,QAAQ,IAAI,EAAE,EAAE;EACpD;EACA,MAAM,KAAK,6EAA6E;EACxF,MAAM,KAAK,2EAA2E;EACtF,MAAM,KAAK,qCAAqC;EAChD;EACA,MAAM,KAAK,wEAAwE;CACvF,CAAC,CAAC,KAAK,IAAI;AACf;;;;;;;;AASA,SAAgB,4BAA4B,OAA4B;CACpE,IAAI,UAAU,MAAM;CAEpB,MAAM,WAAW,KAAK,QAAQ,QAAQ,IAAI,GAAG,KAAK;CAClD,IAAI,GAAG,WAAW,QAAQ,GAAG;CAE7B,SAAS,EAAE;CACX,SAAS,+BAA+B,OAAO,QAAQ,CAAC;CACxD,SAAS,EAAE;CACX,MAAM,IAAI,uBAAuB,OAAO,QAAQ;AACpD;;;;;;AC5DA,SAAgB,eAAe,SAA0C;CACrE,OAAO,QAAQ,OAAO,SAAS,SAAS;AAC5C;;;;AC8BA,SAAgB,YAAY,MAAiB,gBAAkC;CAC3E,OAAO,KAAK,UAAU,WAAW,KAC1B,KAAK,gBAAgB,WAAW,KAChC,KAAK,QAAQ,WAAW,MACvB,CAAC,kBAAkB,KAAK,QAAQ,WAAW;AACvD;;;;;;;;AASA,SAAgB,UAAU,WAAiB,KAAmB;CAC1D,OAAO,KAAK,OAAO,IAAI,QAAQ,IAAI,UAAU,QAAQ,KAAK,KAAU;AACxE;;;;;;;;AASA,SAAgB,eAAe,OAA8B;CACzD,MAAM,QAAQ,qBAAqB,KAAK,MAAM,KAAK,CAAC;CACpD,IAAI,CAAC,OAAO,OAAO;CAEnB,MAAM,SAAS,OAAO,MAAM,EAAE;CAC9B,IAAI,CAAC,OAAO,SAAS,MAAM,GAAG,OAAO;CAErC,OAAO,MAAM,EAAE,EAAE,YAAY,MAAM,MAAM,SAAS,IAAI;AAC1D;AAEA,SAAgB,UACZ,OAMA,UAAyD,CAAC,GACjD;CACT,MAAM,MAAM,QAAQ,uBAAO,IAAI,KAAK;CACpC,MAAM,UAAU,IAAI,IAAI,MAAM,SAAS;CACvC,MAAM,aAAa,IAAI,IAAI,MAAM,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC;CAqB9D,OAAO;EAAE,WAnBS,MAAM,KAAK,QAAQ,QAAQ,CAAC,QAAQ,IAAI,IAAI,MAAM,CAmB3D;EAAW,iBAjBI,MAAM,UACzB,QAAQ,SAAS,KAAK,WAAW,MAAM,YAAY,KAAK,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC,CAC9E,KAee;EAAiB,SAbrB,QAAQ,iBAAiB,OACnC,CAAC,IACD,MAAM,KAIH,QAAQ,QAAQ,QAAQ,IAAI,IAAI,MAAM,CAAC,CAAC,CACxC,KAAK,YAAY;GAAE;GAAQ,SAAS,UAAU,OAAO,WAAW,GAAG;EAAE,EAAE,CAAC,CACxE,QAAQ,UAAU,MAAM,WAAW,QAAQ,aAAc,CAAC,CAC1D,MAAM,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO;EAIC,SAF9B,MAAM,UAAU,QAAQ,SAAS,KAAK,SAAS,WAAW,CAAC,CAAC,CAAC,KAE/B;CAAQ;AAC1D;;;ACvDA,IAAM,eAAe,KAAK,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BhE,SAAS,mBAAmB,MAEkB;CAC1C,MAAM,QAAQ,KAAK,KAAK,cAAc,UAAU,GAAG,KAAK,IAAI;CAC5D,MAAM,SAAS,KAAK,KAAK,cAAc,UAAU,GAAG,KAAK,IAAI;CAC7D,MAAM,SAAS,GAAG,WAAW,KAAK,IAAI,QAAQ,GAAG,WAAW,MAAM,IAAI,SAAS;CAC/E,IAAI,CAAC,QAAQ,OAAO;EAAE,IAAI;EAAO,QAAQ;CAAS;CAElD,MAAM,SAAS,gBAAgB,KAAK;CACpC,IAAI,CAAC,QAAQ,OAAO;EAAE,IAAI;EAAO,QAAQ;CAAM;CAE/C,OAAO;EAAE,IAAI;EAAM,KAAK;EAAQ;CAAO;AAC3C;;AAGA,SAAS,iBAAiB,MAAc,QAAkC;CACtE,IAAI,WAAW,OACX,OAAO,0CAA0C,KAAK;CAG1D,OAAO,kBAAkB,KAAK;AAElC;AAIA,eAAe,UAAyB;CACpC,IAAI;EACA,MAAM,SAAS,MAAM,OAAO;EAC5B,MAAM,WAAW;GACb,QAAQ,IAAI;GACZ,KAAK,QAAQ,QAAQ,IAAI,GAAG,MAAM;GAClC,KAAK,QAAQ,QAAQ,IAAI,GAAG,SAAS;GACrC,KAAK,QAAQ,QAAQ,IAAI,GAAG,YAAY;EAC5C,CAAC,CAAC,OAAO,OAAO;EAEhB,KAAK,MAAM,KAAK,UACZ,IAAI,GAAG,WAAW,CAAC,GAAG;GAClB,MAAM,SAAS,OAAO,OAAO;IAAE,MAAM;IAAG,OAAO;GAAK,CAAC;GACrD,IAAI,OAAO,QAAQ;IACf,KAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,OAAO,MAAM,GACjD,IAAI,QAAQ,IAAI,SAAS,KAAA,GACrB,QAAQ,IAAI,OAAO;IAG3B;GACJ;EACJ;CAER,QAAQ,CAER;AACJ;AAEA,eAAsB,iBAAiB,MAAgB;CAKnD,IAAI,QAAQ,IAAI,wBAAwB,KAAA,GACpC,QAAQ,IAAI,sBAAsB;CAEtC,MAAM,QAAQ;CACd,MAAM,SAAS,KAAK;CACpB,MAAM,aAAa,KAAK;CAOxB,iBAAiB,QAAQ,YAAY,IAAI;CAczC,4BAA4B,kBAAkB,IAAI,CAAC;CAEnD,IAAI,WAAW,MACX,MAAM,UAAU,YAAY,IAAI;MAC7B,IAAI,WAAW,UAClB,MAAM,cAAc,YAAY,IAAI;MACjC,IAAI,WAAW,UAClB,MAAM,oBAAoB,IAAI;MAC3B;EACH,SAAS,MAAM,IAAI,2BAA2B,QAAQ,CAAC;EACvD,QAAQ,KAAK,CAAC;CAClB;AACJ;;AAGA,SAAS,qBAA+B;CACpC,MAAM,MAAM,KAAK,QAAQ,QAAQ,IAAI,GAAG,WAAW,YAAY;CAC/D,IAAI,CAAC,GAAG,WAAW,GAAG,GAAG,OAAO,CAAC;CACjC,OAAO,GAAG,YAAY,GAAG,CAAC,CAAC,QAAO,MAAK,EAAE,SAAS,MAAM,CAAC,CAAC,CAAC,KAAK;AACpE;;;;;;;AAQA,SAAS,yBAAwC;CAC7C,MAAM,SAAS,mBAAmB,CAAC,CAAC,GAAG,EAAE;CACzC,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,QAAQ,SAAS,KAAK,MAAM;CAClC,OAAO,QAAQ,MAAM,KAAK,OAAO,QAAQ,UAAU,EAAE;AACzD;;;;;;;;;;;;;;;;;;;AAoBA,eAAe,kCAAkC,iBAA2C;CAOxF,MAAM,WAAW;EACb,GAAG,MAAM,kBAAkB,eAAe;EAC1C,GAAG,MAAM,kBAAkB,eAAe;EAC1C,GAAG,MAAM,mBAAmB,eAAe;CAC/C;CACA,IAAI,SAAS,WAAW,GAAG,OAAO;CAElC,MAAM,SAAS,mBAAmB,CAAC,CAAC,GAAG,EAAE;CACzC,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,OAAO,KAAK,QAAQ,QAAQ,IAAI,GAAG,WAAW,cAAc,MAAM;CAExE,MAAM,SAAS,yBAAyB,GAAG,aAAa,MAAM,OAAO,GAAG,QAAQ;CAQhF,IAAI,OAAO,UAAU,SAAS,GAAG;EAC7B,SAAS,MAAM,IACX,SAAS,OAAO,iEACpB,CAAC;EACD,SAAS,MAAM,IAAI,uBAAuB,CAAC;EAC3C,KAAK,MAAM,aAAa,OAAO,WAC3B,SAAS,MAAM,KAAK,UAAU,UAAU,QAAQ,QAAQ,GAAG,GAAG,CAAC;EAEnE,SAAS,MAAM,KACX,6KAGJ,CAAC;EACD,QAAQ,KAAK,CAAC;CAClB;CAEA,IAAI,OAAO,QAAQ,WAAW,GAAG,OAAO;CAExC,IAAI,OAAO,OAAO;EACd,GAAG,OAAO,IAAI;EACd,IAAI,MAAM,KACN,eAAe,OAAO,kGAE1B,CAAC;CACL,OAAO;EACH,GAAG,cAAc,MAAM,OAAO,KAAK,OAAO;EAC1C,IAAI,MAAM,KAAK,wCAAwC,OAAO,IAAI,OAAO,QAAQ,OAAO,eAAe,CAAC;CAC5G;CAEA,MAAM,SAAS,WAAW;EAAC;EAAQ;EAAS;CAA2B,GAAG,eAAe;CACzF,OAAO,CAAC,OAAO;AACnB;AAEA,eAAe,UAAU,YAAoB,SAAkC;CAC3E,MAAM,gBAAgB;EAAC;EAAQ;EAAY;EAAW;EAAU;EAAU;EAAW;CAAS;CAC9F,IAAI,CAAC,cAAc,CAAC,cAAc,SAAS,UAAU,GAAG;EACpD,SAAS,MAAM,IAAI,8BAA8B,cAAc,KAAK,IAAI,GAAG,CAAC;EAC5E,QAAQ,KAAK,CAAC;CAClB;CAQA,IAAI,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,IAAI,GAAG;EACtD,IAAI,EAAE;EACN,IAAI,MAAM,KAAK,eAAe,YAAY,CAAC;EAC3C,IAAI,MAAM,KAAK,oFAAoF,CAAC;EACpG,IAAI,EAAE;EACN;CACJ;CAEA,IAAI,eAAe,UAAU;EACzB,MAAM,cAAc,OAAO;EAC3B;CACJ;CAEA,IAAI,eAAe,YAAY,eAAe,aAAa,eAAe,WAAW;EACjF,MAAM,EAAE,eAAe,gBAAgB,mBAAmB,MAAM,OAAO;EAKvE,IAAI,eAAe,YAAY,eAAe,OAAO,MAAM,QAAQ,MAAM,eAAe,OAAO;OAC1F,IAAI,eAAe,UAAU,MAAM,cAAc,OAAO;OACxD,IAAI,eAAe,WAAW,MAAM,eAAe,OAAO;OAC1D,MAAM,eAAe,OAAO;EACjC;CACJ;CAEA,MAAM,YAAA,GAAA,WAAA,QAAA,CACF;EACI,iBAAiB;EACjB,uBAAuB;EACvB,aAAa;EACb,SAAS;EACT,cAAc;EACd,MAAM;EACN,MAAM;CACV,GACA;EACI,MAAM,QAAQ,MAAM,CAAC;EACrB,YAAY;CAChB,CACJ;CACA,MAAM,kBAAkB,SAAS,oBAAoB,KAAK,KAAK,MAAM,UAAU,aAAa;CAE5F,IAAI,eAAe,YAAY;EAC3B,IAAI,EAAE;EACN,IAAI,MAAM,KAAK,yBAAyB,CAAC;EACzC,IAAI,MAAM,KAAK,0EAA0E,CAAC;EAC1F,IAAI,EAAE;EACN,MAAM,cAAc,YAAY,OAAO;EACvC,MAAM,2BAA2B,OAAO;EACxC,IAAI,EAAE;EACN,IAAI,MAAM,KAAK,0DAA0D,CAAC;EAC1E,IAAI,EAAE;EACN,MAAM,gBAAgB,SAAS,EAAE,MAAM;EACvC,MAAM,mBAAmB,mBAAmB;EAC5C,MAAM,SAAS,WAAW;GAAC;GAAQ;GAAe;GAAS;GAA6B;GAAQ;EAA2B,GAAG,eAAe;EAI7I,IAAI,oBAAoB,mBAAmB,CAAC,CAAC,SAAS,iBAAiB;EACvE,IAAI,mBACA,oBAAoB,MAAM,kCAAkC,eAAe;EAa/E,IAAI;GACA,MAAM,gBAAgB,KAAK,QAAQ,QAAQ,IAAI,GAAG,WAAW,YAAY;GACzE,IAAI,GAAG,WAAW,aAAa,KAAK,mBAAmB;IAEnD,MAAM,WADQ,GAAG,YAAY,aACZ,CAAA,CACZ,QAAO,MAAK,EAAE,SAAS,MAAM,CAAC,CAAC,CAC/B,KAAK;IACV,IAAI,SAAS,SAAS,GAAG;KACrB,MAAM,sBAAsB,KAAK,KAAK,eAAe,SAAS,SAAS,SAAS,EAAE;KAKlF,IAAI,mBAAmB,GAAG,aAAa,qBAAqB,OAAO;KACnE,mBAAmB,iBAAiB,QAChC,8CACA,iCACJ;KAYA,MAAM,gBAAgB,cAAc;KACpC,IAAI,eAAe;MACf,mBAAmB,GAAG,iBAAiB,MAAM;MAC7C,IAAI,MAAM,KAAK,0CAA0C,CAAC;KAC9D;KAEA,MAAM,gBAAgB,cAAc;KACpC,IAAI,eAAe;MAaf,MAAM,EAAE,6BAA6B,MAAM,OAAO,4CAAA,CAAA,MAAA,MAAA,EAAA,CAAA;MAClD,MAAM,qBAAqB,6BACvB,qBAAqB,gBAAgB,GACrC,yBAAyB,MAAM,sBAAsB,eAAe,CAAC,CACzE;MACA,MAAM,WAAW,sBAAsB,kBAAkB;MACzD,IAAI,UAAU;OACV,mBAAmB,GAAG,SAAS,IAAI;OACnC,KAAK,MAAM,YAAY,oBACnB,IAAI,MAAM,KAAK,OAAO,iBAAiB,QAAQ,EAAE,6CAA6C,CAAC;MAEvG;MACA,mBAAmB,GAAG,iBAAiB,MAAM;MAC7C,IAAI,MAAM,KAAK,0CAA0C,CAAC;KAC9D;KAIA,MAAM,kBAAkB,gBAAgB;KACxC,IAAI,iBAAiB;MACjB,mBAAmB,GAAG,iBAAiB,MAAM;MAC7C,IAAI,MAAM,KAAK,qDAAqD,CAAC;KACzE;KAEA,GAAG,cAAc,qBAAqB,kBAAkB,OAAO;KAM/D,MAAM,eAAe,KAAK,QAAQ,QAAQ,IAAI,GAAG,WAAW,cAAc;KAC1E,IAAI,GAAG,WAAW,YAAY,GAAG;MAC7B,MAAM,kBAAkB,GAAG,aAAa,cAAc,OAAO;MAC7D,GAAG,eAAe,qBAAqB,SAAS,oBAAoB,OAAO,eAAe;MAC1F,IAAI,MAAM,KAAK,gDAAgD,KAAK,SAAS,mBAAmB,GAAG,CAAC;MAGpG,IAAI,MAAM,KAAK,iCAAiC,CAAC;MACjD,MAAM,SAAS,WAAW;OAAC;OAAQ;OAAS;MAA2B,GAAG,eAAe;MACzF,IAAI,MAAM,KAAK,wDAAwD,CAAC;KAC5E;IACJ;GACJ;EACJ,SAAS,KAAK;GACV,QAAQ,MAAM,OAAO,yDAAyD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAAG,CAAC;EACrI;EAEA,IAAI,CAAC,mBAMD,IAAI,MAAM,KACN,sVAKJ,CAAC;EAGL,IAAI,EAAE;EACN,IAAI,qBAAqB,MAAM,KAAK,MAAM,mBAAmB,EAAE,2CAA2C;EAC1G,IAAI,EAAE;CACV,OAAO;EACH,IAAI,EAAE;EACN,IAAI,MAAM,KAAK,oBAAoB,WAAW,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,WAAW,MAAM,CAAC,GAAG,CAAC;EAC9F,IAAI,EAAE;EAEN,IAAI,eAAe,QAAQ;GACvB,IAAI,MAAM,KAAK,0EAA0E,CAAC;GAC1F,IAAI,EAAE;GACN,MAAM,cAAc,YAAY,OAAO;GACvC,MAAM,2BAA2B,OAAO;GACxC,IAAI,EAAE;GACN,MAAM,SAAS,SAAS,iBAAiB;GACzC,IAAI,MAAM,KAAK,SACT,iFACA,sDAAsD,CAAC;GAC7D,IAAI,EAAE;GACN,MAAM,cAAc,QAAQ,IAAI;GAIhC,IAAI,eAAe,CAAC,QAChB,MAAM,6BAA6B,WAAW;GAOlD,MAAM,OAAO,MAAM,SACf,UACA;IAAC;IAAS;IAAQ;IAA6B;GAAW,GAC1D,iBACA,EAAE,eAAe,KAAK,CAC1B;GACA,MAAM,cAAc,4BAA4B,IAAI;GAuBpD,MAAM,EAAE,SAAS,aAAa,SAAS,YAAY,qBANxB,cACrB,6BACE,qBAAqB,IAAI,GACzB,MAAM,iCAAiC,WAAW,CACtD,IACE,CAAC,GAGH,kBAAkB,MAAM,kBAAkB,eAAe,IAAI,CAAC,CAClE;GAWA,IAAI,QAAQ;IACR,IAAI,MAAM,KAAK,8CAA8C,CAAC;IAC9D,IAAI,EAAE;IACN,IAAI,KAAK,KAAK,GAAG;KACb,IAAI,MAAM,KAAK,oBAAoB,CAAC;KACpC,IAAI,MAAM,KAAK,KAAK,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAChF,OACI,IAAI,MAAM,MAAM,iEAAiE,CAAC;IAEtF,IAAI,EAAE;IACN,IAAI,YAAY,SAAS,GAAG;KACxB,IAAI,MAAM,KAAK,KAAK,YAAY,OAAO,2DAA2D,CAAC;KACnG,IAAI,MAAM,KAAK,sEAAsE,CAAC;KACtF,IAAI,MAAM,KAAK,uBAAuB,CAAC;KACvC,KAAK,MAAM,YAAY,aACnB,IAAI,MAAM,KAAK,UAAU,iBAAiB,QAAQ,GAAG,CAAC;KAE1D,IAAI,EAAE;IACV;IACA,IAAI,QAAQ,SAAS,GACjB,QAAQ,mCAAmC,OAAO,CAAC;IAEvD,IAAI,YAAY,SAAS,GAAG;KACxB,QAAQ,MAAM,OAAO,SAAS,YAAY,OAAO,wBAAwB,CAAC;KAC1E,KAAK,MAAM,KAAK,aACZ,QAAQ,MAAM,IAAI,UAAU,EAAE,KAAK,GAAG,IAAI,MAAM,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,CAAC,CAAC;KAE1F,QAAQ,EAAE;KACV,QAAQ,MAAM,OAAO,6FAA6F,CAAC;KACnH,QAAQ,EAAE;IACd;IACA,IAAI,MAAM,KAAK,mFAAmF,CAAC;IACnG,IAAI,EAAE;IACN;GACJ;GAKA,IAAI,QAAQ,SAAS,GAAG;IACpB,SAAS,mCAAmC,OAAO,CAAC;IACpD,QAAQ,KAAK,CAAC;GAClB;GAEA,MAAM,mBAAmB,SAAS,2BAA2B,QAAQ,SAAS,aAAa;GAC3F,MAAM,WAAW,iBAAiB;IAC9B,kBAAkB,YAAY;IAC9B;IACA,aAAa,QAAQ,MAAM,UAAU;GACzC,CAAC;GAED,IAAI,YAAY,SAAS,GAAG;IACxB,QAAQ,MAAM,OAAO,4BAA4B,YAAY,OAAO,+CAA+C,CAAC;IACpH,QAAQ,EAAE;IACV,KAAK,MAAM,KAAK,aACZ,QAAQ,MAAM,IAAI,UAAU,EAAE,KAAK,GAAG,IAAI,MAAM,KAAK,EAAE,UAAU,QAAQ,QAAQ,GAAG,CAAC,CAAC;IAE1F,QAAQ,EAAE;IACV,QAAQ,MAAM,OAAO,yBAAyB,CAAC;IAC/C,QAAQ,MAAM,KAAK,KAAK,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAChF,QAAQ,EAAE;IAEV,IAAI,aAAa,UAAU;KACvB,SAAS,MAAM,IAAI,yDAAyD,CAAC;KAC7E,SAAS,MAAM,KAAK,mGAAmG,CAAC;KACxH,QAAQ,KAAK,CAAC;IAClB;IACA,IAAI,aAAa;SAIT,CAAC,MAHmB,cACpB,MAAM,OAAO,2EAA2E,CAC5F,GACgB;MACZ,IAAI,MAAM,KAAK,kCAAkC,CAAC;MAClD,QAAQ,KAAK,CAAC;KAClB;WAGA,QAAQ,MAAM,OAAO,sDAAsD,CAAC;GAEpF;GAEA,IAAI,YAAY,SAAS,KAAK,aAAa;IACvC,KAAK,MAAM,YAAY,aACnB,IAAI,MAAM,KAAK,cAAc,iBAAiB,QAAQ,EAAE,wCAAwC,CAAC;IAErG,MAAM,qBAAqB,aAAa,8BAA8B,WAAW,CAAC;GACtF;GAEA,IAAI;IACA,MAAM,SAAS,UAAU;KAAC;KAAS;KAAQ;KAA6B;IAAgB,GAAG,eAAe;GAC9G,SAAS,KAAK;IAKV,IAAI,YAAY,SAAS,KAAK,aAAa;KACvC,IAAI,MAAM,KAAK,iFAAiF,CAAC;KACjG,MAAM,eAAe,WAAW;IACpC;IACA,MAAM;GACV;GACA,IAAI,EAAE;GAEN,IAAI,aAAa;IACb,MAAM,iBAAiB,aAAa,eAAe;IAInD,MAAM,eAAe,WAAW;IAChC,MAAM,eAAe,WAAW;IAChC,MAAM,iBAAiB,WAAW;IAClC,MAAM,cAAc,WAAW;IAC/B,MAAM,kBAAkB,aAAa,eAAe;IACpD,MAAM,kBAAkB,WAAW;IACnC,MAAM,uBAAuB,WAAW;IASxC,IAAI,4BACA,MAAM,gBAAgB,aAAa,kBAAkB,WAAW,CAAC;GAEzE,OACI,QAAQ,MAAM,OAAO,iFAAiF,CAAC;EAE/G,OAAO,IAAI,eAAe,WAAW;GACjC,MAAM,cAAc,QAAQ,IAAI;GAChC,IAAI,aACA,MAAM,6BAA6B,WAAW;GAElD,MAAM,YAAY,SAAS,EAAE,QAAO,QAAO,QAAQ,SAAS;GAM5D,MAAM,WAAW,SAAS;GAC1B,IAAI,UAAU;IACV,IAAI,MAAM,KAAK,eAAe,SAAS,uDAAuD,CAAC;IAC/F,IAAI,EAAE;GACV;GACA,MAAM,SACF,WACA;IACI;IACA;IAAS;IACT,GAAI,WAAW,CAAC,cAAc,QAAQ,IAAI,CAAC;IAC3C,GAAG;GACP,GACA,eACJ;GACA,IAAI,aAAa;IACb,MAAM,kBAAkB,WAAW;IACnC,MAAM,uBAAuB,WAAW;GAC5C;EACJ;EAEA,IAAI,EAAE;EACN,IAAI,MAAM,MAAM,iBAAiB,WAAW,yBAAyB,CAAC;EACtE,IAAI,EAAE;CACV;AACJ;AAEA,eAAe,6BAA6B,aAAoC;CAC5E,IAAI;EACA,MAAM,EAAE,WAAW,MAAM,OAAO;EAChC,MAAM,SAAS,IAAI,OAAO,EAAE,kBAAkB,YAAY,CAAC;EAC3D,MAAM,OAAO,QAAQ;EACrB,IAAI;GASA,MAAM,OAAO,MAAM,iBAAiB;EACxC,UAAU;GACN,MAAM,OAAO,IAAI;EACrB;CACJ,SAAS,KAAK;EACV,QAAQ,MAAM,OAAO,uDAAuD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAAG,CAAC;CACnI;AACJ;;;;;;;;;;;;AAaA,eAAe,iBAAiB,aAAqB,iBAAwC;CACzF,IAAI;EACA,MAAM,EAAE,YAAY,MAAM,OAAO;EACjC,MAAM,EAAE,0BAA0B,MAAM,OAAO,8BAAA,CAAA,MAAA,MAAA,EAAA,CAAA;EAC/C,MAAM,EAAE,oBAAoB,MAAM,OAAO,uBAAA,CAAA,MAAA,MAAA,EAAA,CAAA;EACzC,MAAM,EAAE,WAAW,MAAM,OAAO;EAIhC,MAAM,kBAAiB,MAFG,gBAAgB,KAAK,QAAQ,QAAQ,IAAI,GAAG,eAAe,CAAC,EAAA,CAEnD,MAAM,MAAM;GAC3C,MAAM,IAAI,EAAE;GACZ,OAAO,MAAM,QAAS,OAAO,MAAM,YAAY,MAAM,QAAQ,EAAE,YAAY;EAC/E,CAAC;EAED,MAAM,SAAS,IAAI,OAAO,EAAE,kBAAkB,YAAY,CAAC;EAC3D,MAAM,OAAO,QAAQ;EACrB,IAAI;GACA,MAAM,sBAAsB,QAAQ,MAAM,GAAG,cAAc;EAC/D,UAAU;GACN,MAAM,OAAO,IAAI;EACrB;CACJ,SAAS,KAAK;EACV,QAAQ,MAAM,OAAO,iDAAiD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAAG,CAAC;CAC7H;AACJ;;;;;;;AAQA,eAAe,kBAAkB,aAAoC;CAcjE,MAAM,UAAU,CAAC,UAAU,QAAQ;CACnC,IAAI;CACJ,IAAI;EACA,MAAM,MAAM,OAAO,gCAAA,CAAA,MAAA,MAAA,EAAA,CAAA;CACvB,SAAS,KAAK;EAGV,SAAS,MAAM,IACX,qDAAqD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GACxG,CAAC;EACD;CACJ;CAEA,IAAI;EACA,MAAM,EAAE,WAAW,MAAM,OAAO;EAChC,MAAM,SAAS,IAAI,OAAO,EAAE,kBAAkB,YAAY,CAAC;EAC3D,MAAM,OAAO,QAAQ;EACrB,IAAI;GACA,MAAM,SAAS,OAAO,UAAkB,MAAM,OAAO,MAAM,IAAI,EAAA,CAAG;GAElE,KAAI,MADkB,IAAI,wBAAwB,MAAM,EAAA,CAC5C,YAAY;IACpB,MAAM,IAAI,cAAc,QAAQ,OAAO;IACvC,IAAI,MAAM,KAAK,iBAAiB,IAAI,iBAAiB,yBAAyB,CAAC;GACnF;EACJ,UAAU;GACN,MAAM,OAAO,IAAI;EACrB;CACJ,SAAS,KAAK;EACV,SAAS,MAAM,IACX,iDAAiD,IAAI,iBAAiB,mCACtD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GACnE,CAAC;EACD,SAAS,MAAM,KAAK,IAAI,yBAAyB,sBAAsB,OAAO,CAAC,CAAC;CACpF;AACJ;;;;;;;;;;AAWA,eAAe,uBAAuB,aAAoC;CACtE,IAAI;EACA,MAAM,EAAE,WAAW,MAAM,OAAO;EAChC,MAAM,SAAS,IAAI,OAAO,EAAE,kBAAkB,YAAY,CAAC;EAC3D,MAAM,OAAO,QAAQ;EACrB,IAAI;GACA,MAAM,qBACF,OAAO,UAAU,MAAM,OAAO,MAAM,IAAI,EAAA,CAAG,MAC3C;IACI,OAAO,MAAM,IAAI,MAAM,KAAK,KAAK,GAAG,CAAC;IACrC,OAAO,MAAM,QAAQ,MAAM,OAAO,SAAS,GAAG,CAAC;GACnD,CACJ;EACJ,UAAU;GACN,MAAM,OAAO,IAAI;EACrB;CACJ,QAAQ,CAER;AACJ;AAEA,eAAe,cAAc,aAAoC;CAC7D,IAAI;EACA,MAAM,eAAe,KAAK,QAAQ,QAAQ,IAAI,GAAG,WAAW,cAAc;EAC1E,IAAI,CAAC,GAAG,WAAW,YAAY,GAAG;EAElC,IAAI,MAAM,KAAK,kDAAkD,CAAC;EAClE,IAAI,EAAE;EAEN,MAAM,kBAAkB,GAAG,aAAa,cAAc,OAAO;EAC7D,MAAM,EAAE,WAAW,MAAM,OAAO;EAChC,MAAM,SAAS,IAAI,OAAO,EAAE,kBAAkB,YAAY,CAAC;EAC3D,MAAM,OAAO,QAAQ;EACrB,IAAI;GACA,MAAM,OAAO,MAAM,eAAe;GAClC,IAAI,MAAM,MAAM,wCAAwC,CAAC;EAC7D,UAAU;GACN,MAAM,OAAO,IAAI;EACrB;CACJ,SAAS,KAAK;EACV,MAAM,OAAO,gBAAgB,KAAK,WAAW;EAC7C,IAAI,MACA,SAAS,IAAI;OAEb,SAAS,MAAM,IAAI,qCAAqC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAAG,CAAC;EAE/G,QAAQ,KAAK,CAAC;CAClB;AACJ;;;;;;;;;;;;;;AAeA,eAAe,kBAAkB,aAAqB,iBAAwC;CAC1F,IAAI;EACA,MAAM,EAAE,kBAAkB,sBAAsB,mBAAmB,aAC/D,MAAM,OAAO,6BAAA,CAAA,MAAA,MAAA,EAAA,CAAA;EACjB,MAAM,EAAE,oBAAoB,MAAM,OAAO,uBAAA,CAAA,MAAA,MAAA,EAAA,CAAA;EAEzC,MAAM,cAAc,MAAM,gBAAgB,KAAK,QAAQ,QAAQ,IAAI,GAAG,eAAe,CAAC;EACtF,MAAM,EAAE,WAAW,MAAM,OAAO;EAChC,MAAM,SAAS,IAAI,OAAO,EAAE,kBAAkB,YAAY,CAAC;EAC3D,MAAM,OAAO,QAAQ;EACrB,IAAI;GACA,MAAM,QAAQ,MAAM,iBAAiB,QAAiB,WAAW;GACjE,MAAM,EAAE,SAAS,SAAS,MAAM,qBAAqB,QAAiB,OAAO,WAAW;GAExF,KAAK,MAAM,KAAK,SACZ,IAAI,MAAM,KAAK,kCAAkC,EAAE,KAAK,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC;GAEzF,IAAI,QAAQ,SAAS,GACjB,IAAI,MAAM,MAAM,eAAe,QAAQ,OAAO,kBAAkB,QAAQ,WAAW,IAAI,WAAW,WAAW,EAAE,CAAC;GAKpH,IAAI,KAAK,SAAS,GAAG;IACjB,QAAQ,MAAM,OAAO,8DAA8D,CAAC;IACpF,KAAK,MAAM,KAAK,MACZ,QAAQ,MAAM,OAAO,YAAY,EAAE,OAAO,GAAG,EAAE,MAAM,MAAM,EAAE,KAAK,KAAK,EAAE,QAAQ,MAAM,EAAE,MAAM,KAAK,IAAI,EAAE,EAAE,CAAC;IAEjH,QAAQ,MAAM,OAAO,uEAAuE,CAAC;GACjG;GAIA,MAAM,YAAY;IAAE,GAAG;IAAO,UAAU;GAAK;GAC7C,IAAI,SAAS,SAAS,MAAM,UAAU,QAAQ,SAAS,KAAK,UAAU,SAAS,SAAS,IAAI;IACxF,QAAQ,MAAM,OAAO,mDAAmD,CAAC;IACzE,QAAQ,kBAAkB;KAAE,GAAG;KAAW,UAAU,CAAC;IAAE,CAAC,CAAC;GAC7D;EACJ,UAAU;GACN,MAAM,OAAO,IAAI;EACrB;CACJ,SAAS,KAAK;EACV,QAAQ,MAAM,OAAO,2CAA2C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAAG,CAAC;CACvH;AACJ;;;;;;;;;;;AAYA,IAAM,eAAe;CACjB,gBAAgB;CAChB,sBAAsB;CACtB,UAAU;CACV,SAAS;CACT,MAAM;AACV;AAEA,eAAe,cAAc,SAAkC;CAC3D,MAAM,eAAe,QAAQ;CAE7B,IAAI,CAAC,gBAAgB,iBAAiB,UAAU;EAC5C,gBAAgB;EAChB;CACJ;CAIA,MAAM,SAAS,qBAAqB,QAAQ,MAAM,CAAC,CAAC;CACpD,IAAI,OAAO,SAAS,GAAG;EACnB,SAAS,EAAE;EACX,SAAS,MAAM,IAAI,0BAA0B,OAAO,SAAS,IAAI,MAAM,GAAG,IAAI,OAAO,KAAK,GAAG,GAAG,CAAC;EACjG,SAAS,EAAE;EACX,SAAS,MAAM,KAAK,KAAK,MAAM,KAAK,kBAAkB,EAAE,oDAAoD,CAAC;EAC7G,SAAS,MAAM,KAAK,gDAAgD,CAAC;EACrE,IAAI,QAAQ,IACR,SAAS,MAAM,KAAK,mBAAmB,MAAM,KAAK,oBAAoB,aAAa,GAAG,CAAC,QAAQ,IAAI,GAAG,MAAM,CAAC,CAAC,KAAK,GAAG,GAAG,GAAG,CAAC;EAEjI,SAAS,EAAE;EACX,QAAQ,KAAK,CAAC;CAClB;CAGA,IAAI;EACA,MAAM,SAAS,MAAM,OAAO;EAC5B,MAAM,UAAU,QAAQ,IAAI;EAC5B,IAAI,SACA,OAAO,OAAO;GAAE,MAAM;GAAS,OAAO;EAAK,CAAC;OAE5C,OAAO,OAAO,EAAE,OAAO,KAAK,CAAC;CAErC,QAAQ,CAER;CAEA,MAAM,cAAc,QAAQ,IAAI,gBAAgB,QAAQ,IAAI;CAC5D,IAAI,CAAC,aAAa;EACd,SAAS,MAAM,IAAI,oEAAoE,CAAC;EACxF,QAAQ,KAAK,CAAC;CAClB;CAGA,MAAM,EAAE,wBAAwB,MAAM,OAAO,oCAAA,CAAA,MAAA,MAAA,EAAA,CAAA;CAC7C,MAAM,EAAE,kBAAkB,MAAM,OAAO,8BAAA,CAAA,MAAA,MAAA,EAAA,CAAA;CACvC,MAAM,EAAE,YAAY,MAAM,OAAO;CACjC,MAAM,EAAE,SAAS,MAAM,OAAO;CAE9B,MAAM,OAAO,IAAI,KAAK;EAAE,kBAAkB;EAC9C,KAAK;CAAE,CAAC;CACJ,MAAM,KAAK,QAAQ,IAAI;CACvB,MAAM,cAAc,IAAI,oBAAoB,WAAW;CACvD,MAAM,gBAAgB,IAAI,cAAc,IAAI,WAAW;CAGvD,MAAM,cAAc,0BAA0B;CAE9C,IAAI;EACA,QAAQ,cAAR;GACI,KAAK,UAAU;IACX,MAAM,OAAO,QAAQ;IACrB,IAAI,CAAC,MAAM;KACP,SAAS,MAAM,IAAI,4BAA4B,CAAC;KAChD,IAAI,MAAM,KAAK,2DAA2D,CAAC;KAC3E,QAAQ,KAAK,CAAC;IAClB;IACA,IAAI;IACJ,MAAM,UAAU,QAAQ,QAAQ,QAAQ;IACxC,IAAI,YAAY,MAAM,QAAQ,UAAU,IACpC,SAAS,QAAQ,UAAU;IAE/B,MAAM,QAAQ,QAAQ,SAAS,SAAS;IACxC,IAAI,EAAE;IACN,IAAI,MAAM,KAAK,kCAAkC,CAAC;IAClD,IAAI,MAAM,KAAK,aAAa,MAAM,CAAC;IACnC,IAAI,QAAQ,IAAI,MAAM,KAAK,aAAa,QAAQ,CAAC;IACjD,IAAI,OAAO,IAAI,MAAM,KAAK,gEAAgE,CAAC;IAC3F,IAAI,EAAE;IACN,MAAM,SAAS,MAAM,cAAc,aAAa,MAAM;KAAE;KAAQ;IAAM,CAAC;IACvE,IAAI,MAAM,MAAM,eAAe,OAAO,KAAK,wBAAwB,CAAC;IACpE,IAAI,MAAM,KAAK,oBAAoB,OAAO,MAAM,CAAC;IACjD,IAAI,MAAM,KAAK,iBAAiB,OAAO,gBAAgB,CAAC;IACxD,IAAI,EAAE;IACN;GACJ;GAEA,KAAK,QAAQ;IACT,MAAM,WAAW,MAAM,cAAc,aAAa;IAClD,IAAI,EAAE;IACN,IAAI,SAAS,WAAW,GACpB,IAAI,MAAM,KAAK,sEAAsE,CAAC;SACnF;KACH,IAAI,MAAM,KAAK,QAAQ,SAAS,OAAO,aAAa,CAAC;KACrD,IAAI,EAAE;KACN,KAAK,MAAM,KAAK,UAAU;MACtB,MAAM,OAAO,EAAE,aAAa,OACtB,MAAM,KAAK,KAAK,YAAY,EAAE,SAAS,EAAE,EAAE,IAC3C;MACN,MAAM,MAAM,MAAM,KAAK,cAAc,QAAQ,EAAE,SAAS,GAAG;MAC3D,IAAI,KAAK,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,KAAK,EAAE,IAAI,IAAI,OAAO,KAAK;MAC9D,IAAI,MAAM,KAAK,YAAY,EAAE,gBAAgB,CAAC;KAClD;IACJ;IACA,IAAI,EAAE;IACN;GACJ;GAEA,KAAK,UAAU;IACX,MAAM,OAAO,QAAQ;IACrB,IAAI,CAAC,MAAM;KACP,SAAS,MAAM,IAAI,4BAA4B,CAAC;KAChD,IAAI,MAAM,KAAK,yCAAyC,CAAC;KACzD,QAAQ,KAAK,CAAC;IAClB;IACA,IAAI,EAAE;IACN,IAAI,MAAM,KAAK,2BAA2B,KAAK,KAAK,CAAC;IACrD,MAAM,cAAc,aAAa,MAAM,EAAE,OAAO,QAAQ,SAAS,SAAS,EAAE,CAAC;IAC7E,IAAI,MAAM,MAAM,eAAe,KAAK,WAAW,CAAC;IAChD,IAAI,EAAE;IACN;GACJ;GAEA,KAAK,QAAQ;IACT,MAAM,OAAO,QAAQ;IACrB,IAAI,CAAC,MAAM;KACP,SAAS,MAAM,IAAI,4BAA4B,CAAC;KAChD,IAAI,MAAM,KAAK,uCAAuC,CAAC;KACvD,QAAQ,KAAK,CAAC;IAClB;IACA,MAAM,OAAO,MAAM,cAAc,cAAc,IAAI;IACnD,IAAI,EAAE;IACN,IAAI,CAAC,MAAM;KAQP,SAAS,MAAM,IAAI,eAAe,KAAK,aAAa,CAAC;KACrD,IAAI,EAAE;KACN,QAAQ,KAAK,CAAC;IAClB,OAAO;KACH,IAAI,MAAM,KAAK,gBAAgB,KAAK,MAAM,CAAC;KAC3C,IAAI,MAAM,KAAK,oBAAoB,KAAK,MAAM,CAAC;KAC/C,IAAI,MAAM,KAAK,iBAAiB,KAAK,gBAAgB,CAAC;KACtD,IAAI,MAAM,KAAK,iBAAiB,KAAK,UAAU,YAAY,GAAG,CAAC;KAC/D,IAAI,KAAK,aAAa,MAClB,IAAI,MAAM,KAAK,iBAAiB,YAAY,KAAK,SAAS,GAAG,CAAC;IAEtE;IACA,IAAI,EAAE;IACN;GACJ;GAEA,KAAK,SAAS;IACV,MAAM,UAAA,GAAA,WAAA,QAAA,CAAa,cAAc;KAAE,MAAM,QAAQ,MAAM,CAAC;KAAG,YAAY;IAAK,CAAC;IAC7E,MAAM,eAAe,OAAO,mBAAmB;IAC/C,MAAM,gBAAgB,gBAAgB,OAAO,OAAO,eAAe,YAAY;IAC/E,IAAI,gBAAgB,QAAQ,iBAAiB,MAAM;KAC/C,SAAS,MAAM,IAAI,qBAAqB,aAAa,qBAAqB,CAAC;KAC3E,IAAI,MAAM,KAAK,6CAA6C,CAAC;KAC7D,QAAQ,KAAK,CAAC;IAClB;IAEA,MAAM,iBAAiB,OAAO,0BAA0B;IACxD,MAAM,EAAE,MAAM,cAAc,MAAM,cAAc,gBAAgB;IAChE,MAAM,OAAO,UAAU;KAAE;KAAM;KAAW,cAAc;IAAM,GAAG,EAAE,cAAc,CAAC;IAElF,IAAI,EAAE;IACN,IAAI,YAAY,MAAM,cAAc,GAAG;KACnC,IAAI,MAAM,KAAK,qBAAqB,CAAC;KACrC,IAAI,CAAC,iBAAiB,KAAK,SAAS,GAChC,IAAI,MAAM,KAAK,KAAK,KAAK,OAAO,iEAAiE,CAAC;KAEtG,IAAI,CAAC,kBAAkB,KAAK,QAAQ,SAAS,GAAG;MAC5C,IAAI,MAAM,KAAK,KAAK,KAAK,QAAQ,OAAO,mDAAmD,CAAC;MAC5F,IAAI,MAAM,KAAK,yCAAyC,CAAC;KAC7D;KACA,IAAI,EAAE;KACN;IACJ;IAEA,IAAI,MAAM,KAAK,iBAAiB,CAAC;IACjC,IAAI,EAAE;IACN,KAAK,MAAM,OAAO,KAAK,WACnB,IAAI,KAAK,MAAM,OAAO,GAAG,EAAE,GAAG,MAAM,KAAK,IAAI,IAAI,EAAE,GAAG,MAAM,KAAK,mEAAmE,GAAG;IAE3I,KAAK,MAAM,UAAU,KAAK,iBACtB,IAAI,KAAK,MAAM,OAAO,GAAG,EAAE,GAAG,MAAM,KAAK,MAAM,EAAE,GAAG,MAAM,KAAK,iEAAiE,GAAG;IAEvI,KAAK,MAAM,EAAE,QAAQ,aAAa,KAAK,SACnC,IAAI,KAAK,MAAM,IAAI,GAAG,EAAE,GAAG,MAAM,KAAK,OAAO,IAAI,EAAE,GAAG,MAAM,KAAK,KAAK,QAAQ,+CAA+C,GAAG;IAEpI,IAAI,gBACA,KAAK,MAAM,UAAU,KAAK,SACtB,IAAI,KAAK,MAAM,IAAI,GAAG,EAAE,GAAG,MAAM,KAAK,MAAM,EAAE,GAAG,MAAM,KAAK,2CAA2C,GAAG;SAE3G,IAAI,KAAK,QAAQ,SAAS,GAC7B,IAAI,MAAM,KAAK,MAAM,KAAK,QAAQ,OAAO,4DAA4D,CAAC;IAE1G,IAAI,EAAE;IAEN,IAAI,OAAO,aAAa;SAIhB,CAAC,MADmB,cAAc,wBAAwB,GAC9C;MACZ,IAAI,MAAM,KAAK,wBAAwB,CAAC;MACxC,IAAI,EAAE;MACN;KACJ;;IAGJ,IAAI,UAAU;IACd,KAAK,MAAM,OAAO,KAAK,WAAW;KAC9B,MAAM,cAAc,gBAAgB,IAAI,IAAI;KAC5C,WAAW;IACf;IACA,KAAK,MAAM,UAAU,KAAK,iBAAiB;KACvC,MAAM,cAAc,aAAa,MAAM;KACvC,WAAW;IACf;IACA,KAAK,MAAM,EAAE,YAAY,KAAK,SAAS;KACnC,MAAM,cAAc,aAAa,OAAO,IAAI;KAC5C,WAAW;IACf;IACA,IAAI,gBACA,KAAK,MAAM,UAAU,KAAK,SAAS;KAC/B,MAAM,cAAc,aAAa,MAAM;KACvC,WAAW;IACf;IAGJ,IAAI,MAAM,MAAM,cAAc,QAAQ,UAAU,CAAC;IACjD,IAAI,EAAE;IACN;GACJ;GAEA;IACI,SAAS,MAAM,IAAI,2BAA2B,aAAa,GAAG,CAAC;IAC/D,gBAAgB;IAChB,QAAQ,KAAK,CAAC;EACtB;CACJ,UAAU;EACN,MAAM,YAAY,SAAS;EAC3B,MAAM,KAAK,IAAI;CACnB;AACJ;AAEA,SAAS,kBAAkB;CACvB,IAAI;EACN,MAAM,KAAK,kBAAkB,EAAE;;EAE/B,MAAM,MAAM,KAAK,OAAO,EAAE;qBACP,MAAM,KAAK,WAAW,EAAE;;EAE3C,MAAM,MAAM,KAAK,UAAU,EAAE;IAC3B,MAAM,KAAK,KAAK,QAAQ,EAAE;IAC1B,MAAM,KAAK,KAAK,MAAM,EAAE;IACxB,MAAM,KAAK,KAAK,QAAQ,EAAE;IAC1B,MAAM,KAAK,KAAK,QAAQ,EAAE;IAC1B,MAAM,KAAK,KAAK,MAAM,EAAE;IACxB,MAAM,KAAK,KAAK,OAAO,EAAE;;EAE3B,MAAM,MAAM,KAAK,WAAW,EAAE;;;;;;EAM9B,MAAM,MAAM,KAAK,SAAS,EAAE;IAC1B,MAAM,KAAK,KAAK,SAAS,EAAE;;;;IAI3B,MAAM,KAAK,KAAK,oBAAoB,EAAE;;IAEtC,MAAM,KAAK,KAAK,WAAW,EAAE;;;;EAI/B,MAAM,MAAM,KAAK,UAAU,EAAE;IAC3B,MAAM,KAAK,kCAAkC,EAAE;;;;IAI/C,MAAM,KAAK,0CAA0C,EAAE;;;IAGvD,MAAM,KAAK,+DAA+D,EAAE;;;IAG5E,MAAM,KAAK,qBAAqB,EAAE;;;IAGlC,MAAM,KAAK,mBAAmB,EAAE;;CAEnC;AACD;AAEA,SAAS,YAAY,OAAuB;CACxC,IAAI,QAAQ,MAAM,OAAO,GAAG,MAAM;CAClC,IAAI,QAAQ,OAAO,MAAM,OAAO,IAAI,QAAQ,KAAA,CAAM,QAAQ,CAAC,EAAE;CAC7D,IAAI,QAAQ,OAAO,OAAO,MAAM,OAAO,IAAI,SAAS,OAAO,MAAA,CAAO,QAAQ,CAAC,EAAE;CAC7E,OAAO,IAAI,SAAS,OAAO,OAAO,MAAA,CAAO,QAAQ,CAAC,EAAE;AACxD;;AAGA,SAAS,QAAQ,MAAoB;CAGjC,OAAO,mBAAmB,MAAM,EAAE,OAAO,OAAO,kBAAkB,CAAC,KAAK;AAC5E;;AAKA,IAAI,6BAA6B;AAEjC,eAAe,SACX,QACA,MACA,iBACA,OAAoC,CAAC,GACtB;CACf,MAAM,WAAW,gBAAgB,OAAO;CACxC,IAAI,CAAC,UAAU;EAKX,SAAS,MAAM,IAAI,qEAAqE,CAAC;EAOzF,MAAM,UAAU,4BAA4B;EAE5C,MAAM,YAAY,mBAAmB,cAAc;EAEnD,IAAI,cAAc,oBAAoB;GAOlC,SAAS,MAAM,OAAO,8HACmD,CAAC;GAC1E,SAAS,MAAM,KACX,kLAGJ,CAAC;GACD,SAAS,kBAAkB;GAC3B,SAAS,MAAM,KAAK,OAAO,yBAAyB,OAAO,EAAE,GAAG,CAAC;EACrE,OAAO,IAAI,cAAc,wBAAwB;GAC7C,SAAS,MAAM,OAAO,6DAA6D,CAAC;GACpF,SAAS,MAAM,KACX,6SAIJ,CAAC;GACD,SAAS,yBAAyB;GAClC,KAAK,MAAM,QAAQ,0BAA0B,gBAAgB,OAAO,GAChE,SAAS,OAAO,MAAM,KAAK,IAAI,IAAI,EAAE;GAEzC,SAAS,EAAE;EACf,OAAO;GACH,SAAS,MAAM,KAAK,0CAA0C,CAAC;GAC/D,SAAS,sBAAsB;GAC/B,SAAS,MAAM,KAAK,OAAO,sBAAsB,gBAAgB,OAAO,EAAE,GAAG,CAAC;GAC9E,SAAS,MAAM,KACX,0JAEJ,CAAC;EACL;EACA,QAAQ,KAAK,CAAC;CAClB;CAEA,MAAM,MAAM,EAAE,GAAG,QAAQ,IAA8B;CACvD,IAAI;EACA,MAAM,SAAS,MAAM,OAAO;EAC5B,MAAM,WAAW;GACb,QAAQ,IAAI;GACZ,KAAK,QAAQ,QAAQ,IAAI,GAAG,MAAM;GAClC,KAAK,QAAQ,QAAQ,IAAI,GAAG,SAAS;GACrC,KAAK,QAAQ,QAAQ,IAAI,GAAG,YAAY;EAC5C,CAAC,CAAC,OAAO,OAAO;EAEhB,KAAK,MAAM,KAAK,UACZ,IAAI,GAAG,WAAW,CAAC,GAAG;GAClB,MAAM,SAAS,OAAO,OAAO;IAAE,MAAM;IAAG,OAAO;GAAK,CAAC;GACrD,IAAI,OAAO,QAAQ;IACf,KAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,OAAO,MAAM,GACjD,IAAI,IAAI,SAAS,KAAA,GACb,IAAI,OAAO;IAGnB;GACJ;EACJ;CAER,QAAQ,CAER;CAEA,MAAM,cAAc,IAAI;CACxB,IAAI,CAAC,aAAa;EACd,SAAS,MAAM,IAAI,oEAAoE,CAAC;EACxF,QAAQ,KAAK,CAAC;CAClB;CAKA,MAAM,0BAA0B,WAAW;CAE3C,MAAM,iBAAiB,kBAAkB,WAAW;CAIpD,IAAI,MAAM,wBAAwB,aAAa,cAAc,GAAG,6BAA6B;CAK7F,MAAM,WAAW,SAAS,WAAW;CACrC,MAAM,cAAc,SAAS,cAAc;CAW3C,MAAM,WAAqB,CAAC;CAC5B,IAAI,mBAAmB,mBAAmB,QAAQ,IAAI,GAAG;EAGrD,SAAS,KAAK,GAAG,MAAM,kBAAkB,eAAe,CAAC;EACzD,SAAS,KAAK,GAAG,MAAM,kBAAkB,eAAe,CAAC;EACzD,SAAS,KAAK,GAAG,MAAM,mBAAmB,eAAe,CAAC;EAM1D,IAAI;GACA,SAAS,KAAK,GAAG,MAAM,iBAAiB,aAAa,eAAe,CAAC;EACzE,SAAS,KAAK;GACV,IAAI,eAAe,2BAA2B;IAC1C,SAAS,MAAM,IAAI,iEAAiE,CAAC;IACrF,SAAS,MAAM,KAAK,KAAK,IAAI,SAAS,CAAC;IACvC,SAAS,MAAM,KAAK,wFAAwF,CAAC;IAC7G,MAAM,OAAO,gBAAgB,IAAI,SAAS,KAAK,WAAW;IAC1D,IAAI,MAAM,SAAS,IAAI;IACvB,QAAQ,KAAK,CAAC;GAClB;GACA,MAAM;EACV;EAKA,IAAI;GACA,SAAS,KAAK,GAAG,MAAM,wBAAwB,aAAa,eAAe,CAAC;EAChF,SAAS,KAAK;GACV,IAAI,eAAe,2BAA2B;IAC1C,SAAS,MAAM,IAAI,kEAAkE,CAAC;IACtF,SAAS,MAAM,KAAK,KAAK,IAAI,SAAS,CAAC;IACvC,SAAS,MAAM,KAAK,0FAA0F,CAAC;IAC/G,MAAM,OAAO,gBAAgB,IAAI,SAAS,KAAK,WAAW;IAC1D,IAAI,MAAM,SAAS,IAAI;IACvB,QAAQ,KAAK,CAAC;GAClB;GACA,MAAM;EACV;CACJ;CAQA,MAAM,aAAa,MAAM,UANP,eAAe;EAAE;EAAQ;EAAM,KAAK;EAAU,QAAQ;EAAa;CAAS,CAM3D,GAAW;EAC1C,KAAK,QAAQ,IAAI;EACjB,QAAQ,KAAK,gBAAgB,SAAS;EACtC,QAAQ;EACR;CACJ,CAAC;CACD,IAAI,aAAa;CACjB,IAAI,KAAK,eACL,WAAW,QAAQ,GAAG,SAAS,UAAkB;EAC7C,cAAc,MAAM,SAAS;CACjC,CAAC;CAEL,IAAI,aAAa;CACjB,WAAW,QAAQ,GAAG,SAAS,UAAkB;EAC7C,MAAM,OAAO,MAAM,SAAS;EAC5B,cAAc;EACd,QAAQ,OAAO,MAAM,IAAI;CAC7B,CAAC;CACD,IAAI;EACA,MAAM;CACV,QAAQ;EACJ,SAAS,MAAM,IAAI,aAAa,OAAO,GAAG,KAAK,KAAK,GAAG,EAAE,WAAW,CAAC;EAcrE,MAAM,OAAO,MAPW,qBAAqB;GACzC;GACA;GACA,QAAQ;GACR;GACA,wBAAwB,uBAAuB;EACnD,CAAC,KACyB,gBAAgB,EAAE,SAAS,WAAW,GAAG,WAAW;EAC9E,IAAI,MACA,SAAS,IAAI;EAEjB,QAAQ,KAAK,CAAC;CAClB;CAIA,IAAI,KAAK,eACL,OAAO,WAAW,KAAK,CAAC,CAAC,SAAS,IAAI,aAAa;CAEvD,OAAO;AACX;AAEA,eAAe,2BAA2B,SAAkC;CACxE,MAAM,YAAA,GAAA,WAAA,QAAA,CACF;EACI,iBAAiB;EACjB,YAAY;EACZ,MAAM;EACN,MAAM;CACV,GACA;EACI,MAAM,QAAQ,MAAM,CAAC;EACrB,YAAY;CAChB,CACJ;CAEA,MAAM,MAAM,mBAAmB,uBAAuB;CACtD,IAAI,CAAC,IAAI,IAAI;EACT,SAAS,MAAM,IAAI,iBAAiB,iBAAiB,IAAI,MAAM,CAAC,CAAC;EACjE,QAAQ,KAAK,CAAC;CAClB;CAEA,MAAM,kBAAkB,SAAS,oBAAoB,KAAK,KAAK,MAAM,UAAU,aAAa;CAC5F,MAAM,aAAa,SAAS,eAAe,KAAK,KAAK,WAAW,YAAY;CAE5E,MAAM,WAAW;EACb,IAAI;EACJ,IAAI;EACJ,iBAAiB;EACjB,YAAY;CAChB;CAEA,IAAI;EACA,MAAM,MAAM,SAAS,IAAI,SAAS,MAAM,CAAC,GAAG;GACxC,KAAK,QAAQ,IAAI;GACjB,OAAO;GACP,KAAK,EAAE,GAAG,QAAQ,IAA8B;EACpD,CAAC;CACL,SAAS,KAAc;EAKnB,IAAI,OAAQ,IAA8B,aAAa,UACnD,SAAS,MAAM,IAAI,yDAAyD,CAAC;OAE7E,SAAS,MAAM,IAAI,2CAA2C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAAG,CAAC;EAErH,QAAQ,KAAK,CAAC;CAClB;AACJ;;;;;;;;;;;;;;;;;AAkBA,eAAe,mBAAmB,SAAkC;CAChE,MAAM,YAAA,GAAA,WAAA,QAAA,CACF;EACI,iBAAiB;EACjB,YAAY;EACZ,SAAS;EACT,MAAM;EACN,MAAM;EAGN,SAAS;CACb,GACA;EAAE,MAAM,QAAQ,MAAM,CAAC;EAAG,YAAY;CAAK,CAC/C;CAEA,MAAM,kBAAkB,SAAS,oBAAoB,KAAK,KAAK,MAAM,UAAU,aAAa;CAC5F,MAAM,aAAa,SAAS,eAAe,KAAK,KAAK,OAAO,qBAAqB;CACjF,MAAM,aAAa,KAAK,QAAQ,QAAQ,IAAI,GAAG,UAAU;CAEzD,MAAM,MAAM,QAAQ,SAAS,QAAQ;CACrC,MAAM,kBAAkB,GAAG,WAAW,UAAU;CAEhD,MAAM,EAAE,oBAAoB,MAAM,OAAO,uBAAA,CAAA,MAAA,MAAA,EAAA,CAAA;CACzC,MAAM,EAAE,2BAA2B,iBAC/B,MAAM,OAAO,2CAAA,CAAA,MAAA,MAAA,EAAA,CAAA;CAEjB,IAAI,QAAsD,CAAC;CAC3D,IAAI;CACJ,IAAI,iBACA,IAAI;EACA,MAAM,cAAc,MAAM,gBAAgB,KAAK,QAAQ,QAAQ,IAAI,GAAG,eAAe,CAAC;EACtF,QAAQ,0BAA0B,GAAG,aAAa,YAAY,MAAM,GAAG,WAAW;CACtF,SAAS,KAAK;EAKV,aAAa,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;EAC5D,OAAO,MAAM,0BAA0B,WAAW,EAAE;CACxD;CAMJ,MAAM,UAAU,aAAa;EAAE;EAAY;EAAiB;EAAO;EAAY;CAAI,CAAC;CAEpF,KAAK,MAAM,QAAQ,QAAQ,OACvB,IAAI,CAAC,MAAM,IAAI,EAAE;MACZ,IAAI,KAAK,SAAS,IAAI,GAAG,QAAQ,MAAM,OAAO,IAAI,CAAC;MACnD,IAAI,QAAQ,aAAa,GAAG,SAAS,MAAM,IAAI,IAAI,CAAC;MACpD,IAAI,KAAK,SAAS,GAAG,GAAG,IAAI,MAAM,MAAM,IAAI,CAAC;MAC7C,IAAI,MAAM,KAAK,IAAI,CAAC;CAG7B,IAAI,QAAQ,aAAa,GAAG,QAAQ,KAAK,QAAQ,QAAQ;CACzD,IAAI,CAAC,QAAQ,YAAY;CAEzB,MAAM,cAAc,YAAY;EAAC;EAAU;EAAY,iBAAiB;EAAmB,YAAY;CAAY,CAAC;AACxH;AAEA,eAAe,cAAc,YAAoB,SAAkC;CAU/E,IAAI,eAAe,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,IAAI,IAAI;EACtE,IAAI,EAAE;EACN,IAAI,MAAM,KAAK,mBAAmB,YAAY,CAAC;EAC/C,IAAI,MAAM,KAAK,wFAAwF,CAAC;EACxG,IAAI,EAAE;EACN;CACJ;CAEA,IAAI,eAAe,SAAS;EACxB,MAAM,mBAAmB,OAAO;EAChC;CACJ;CAEA,IAAI,eAAe,YAAY;EAC3B,MAAM,YAAA,GAAA,WAAA,QAAA,CACF;GACI,iBAAiB;GACjB,YAAY;GACZ,WAAW;GACX,MAAM;GACN,MAAM;GACN,SAAS;GACT,MAAM;EACV,GACA;GACI,MAAM,QAAQ,MAAM,CAAC;GACrB,YAAY;EAChB,CACJ;EAIA,MAAM,YAAY,mBAAmB,yBAAyB;EAC9D,IAAI,CAAC,UAAU,IAAI;GACf,SAAS,MAAM,IAAI,iBAAiB,oBAAoB,UAAU,MAAM,CAAC,CAAC;GAC1E,QAAQ,KAAK,CAAC;EAClB;EAEA,MAAM,kBAAkB,SAAS,oBAAoB,KAAK,KAAK,MAAM,UAAU,aAAa;EAC5F,MAAM,aAAa,SAAS,eAAe,KAAK,KAAK,OAAO,qBAAqB;EACjF,MAAM,QAAQ,SAAS,cAAc;EAErC,IAAI,EAAE;EACN,IAAI,MAAM,KAAK,8BAA8B,CAAC;EAC9C,IAAI,EAAE;EAEN,MAAM,WAAW;GACb,UAAU;GACV,UAAU;GACV,iBAAiB;GACjB,YAAY;EAChB;EACA,IAAI,OACA,SAAS,KAAK,SAAS;EAG3B,IAAI;GACA,MAAM,MAAM,SAAS,IAAI,SAAS,MAAM,CAAC,GAAG;IACxC,KAAK,QAAQ,IAAI;IACjB,OAAO;IACP,KAAK,EAAE,GAAG,QAAQ,IAA8B;GACpD,CAAC;EACL,SAAS,KAAc;GAGnB,IAAI,OAAQ,IAA8B,aAAa,UACnD,SAAS,MAAM,IAAI,2DAA2D,CAAC;QAE/E,SAAS,MAAM,IAAI,qCAAqC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAAG,CAAC;GAE/G,QAAQ,KAAK,CAAC;EAClB;CACJ,OAAO,IAAI,eAAe,cAAc;EACpC,MAAM,YAAA,GAAA,WAAA,QAAA,CACF;GACI,YAAY;GACZ,iBAAiB;GACjB,WAAW;GACX,YAAY;GACZ,MAAM;GACN,SAAS;GACT,MAAM;GACN,MAAM;EACV,GACA;GACI,MAAM,QAAQ,MAAM,CAAC;GACrB,YAAY;EAChB,CACJ;EAEA,MAAM,aAAa,mBAAmB,eAAe;EACrD,IAAI,CAAC,WAAW,IAAI;GAChB,SAAS,MAAM,IAAI,iBAAiB,wBAAwB,WAAW,MAAM,CAAC,CAAC;GAC/E,QAAQ,KAAK,CAAC;EAClB;EAEA,MAAM,aAAa,SAAS,eAAe,SAAS,oBAAoB,KAAK,KAAK,MAAM,UAAU,aAAa;EAE/G,IAAI,EAAE;EACN,IAAI,MAAM,KAAK,iCAAiC,CAAC;EACjD,IAAI,EAAE;EAEN,MAAM,WAAW;GACb,WAAW;GACX,WAAW;GACX,YAAY;GACZ,GAAI,SAAS,aAAa,CAAC,SAAS,IAAI,CAAC;GACzC,GAAI,SAAS,cAAc,CAAC,YAAY,SAAS,aAAa,IAAI,CAAC;EACvE;EAEA,IAAI;GACA,MAAM,MAAM,SAAS,IAAI,SAAS,MAAM,CAAC,GAAG;IACxC,KAAK,QAAQ,IAAI;IACjB,OAAO;IACP,KAAK,EAAE,GAAG,QAAQ,IAA8B;GACpD,CAAC;EACL,SAAS,KAAc;GACnB,SAAS,MAAM,IAAI,wCAAwC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAAG,CAAC;GAC9G,QAAQ,KAAK,CAAC;EAClB;CACJ,OAAO;EACH,SAAS,MAAM,IAAI,yBAAyB,CAAC;EAC7C,QAAQ,KAAK,CAAC;CAClB;AACJ;AAEA,eAAe,oBAAoB,SAAkC;CACjE,MAAM,cAAA,GAAA,WAAA,QAAA,CACF;EACI,iBAAiB;EACjB,YAAY;EACZ,SAAS;EACT,cAAc;EACd,MAAM;EACN,MAAM;EACN,MAAM;CACV,GACA;EACI,MAAM,QAAQ,MAAM,CAAC;EACrB,YAAY;CAChB,CACJ;CAEA,MAAM,SAAS,mBAAmB,YAAY;CAC9C,IAAI,CAAC,OAAO,IAAI;EACZ,SAAS,MAAM,IAAI,iBAAiB,iBAAiB,OAAO,MAAM,CAAC,CAAC;EACpE,QAAQ,KAAK,CAAC;CAClB;CAEA,MAAM,kBAAkB,WAAW,oBAAoB,KAAK,KAAK,MAAM,UAAU,aAAa;CAC9F,MAAM,aAAa,WAAW,eAAe,KAAK,KAAK,OAAO,qBAAqB;CACnF,MAAM,UAAU,WAAW,YAAY,KAAK,KAAK,MAAM,aAAa,OAAO,mBAAmB;CAE9F,MAAM,WAAW;EACb,OAAO;EACP,OAAO;EACP,iBAAiB;EACjB,YAAY;EACZ,SAAS;EAGT,GAAI,WAAW,gBAAgB,CAAC,YAAY,IAAI,CAAC;CACrD;CAEA,IAAI;EACA,MAAM,MAAM,SAAS,IAAI,SAAS,MAAM,CAAC,GAAG;GACxC,KAAK,QAAQ,IAAI;GACjB,OAAO;GACP,KAAK,EAAE,GAAG,QAAQ,IAA8B;EACpD,CAAC;CACL,QAAQ;EACJ,QAAQ,KAAK,CAAC;CAClB;AACJ;AAIA,IAAM,YAAY,QAAQ,KAAK,KAAK,GAAG,aAAa,QAAQ,KAAK,EAAE,IAAI;AACvE,IAAI,OAAO,KAAK,QAAQ,UAAU,aAE9B,iBAAiB,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,UAAmB;CAC9D,qBAAqB,KAAK;CAC1B,QAAQ,KAAK,CAAC;AAClB,CAAC"}
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/schema/destructive-sql.ts","../src/schema/generated-column-conflicts.ts","../src/schema/carved-out-migration.ts","../src/schema/atlas-argv.ts","../src/branch-argv.ts","../src/cli-flags.ts","../src/cli-collections-path.ts","../src/backup-argv.ts","../src/branch-prune.ts","../src/cli.ts"],"sourcesContent":["/**\n * Pure helpers that classify an Atlas declarative-apply plan as destructive\n * or not, and decide what `rebase db push` should do about it.\n *\n * `db push` runs `atlas schema apply` to make the live database match the\n * generated `schema.sql`. Removing a collection field compiles to\n * `DROP COLUMN`; renaming compiles to drop-then-add — either destroys data.\n * We first run the apply with `--dry-run` to obtain the planned SQL, scan it\n * here, and refuse to auto-approve anything destructive without an explicit\n * opt-in.\n *\n * Everything in this file is side-effect free so it can be unit-tested\n * without Atlas or a database.\n */\n\n/**\n * SQL fragments that destroy data or data-bearing objects. Matched\n * case-insensitively against each statement of the plan. `IF EXISTS` /\n * whitespace variations are tolerated by the regexes below.\n */\nconst DESTRUCTIVE_PATTERNS: { label: string; re: RegExp }[] = [\n { label: \"DROP TABLE\", re: /\\bDROP\\s+TABLE\\b/i },\n { label: \"DROP COLUMN\", re: /\\bDROP\\s+COLUMN\\b/i },\n { label: \"DROP SCHEMA\", re: /\\bDROP\\s+SCHEMA\\b/i },\n { label: \"DROP VIEW\", re: /\\bDROP\\s+(MATERIALIZED\\s+)?VIEW\\b/i },\n { label: \"DROP TYPE\", re: /\\bDROP\\s+TYPE\\b/i },\n { label: \"TRUNCATE\", re: /\\bTRUNCATE\\b/i }\n];\n\n/**\n * Split a SQL script into individual statements, dropping blank lines and\n * `--` comment lines. Deliberately simple: Atlas emits one plain statement\n * per `;`, without string literals that contain semicolons in a schema DDL\n * plan, so a naive split is safe and keeps this dependency-free.\n */\nexport function splitSqlStatements(sql: string): string[] {\n // Strip full-line SQL comments so a commented-out DROP never trips the\n // detector, then split on semicolons.\n const withoutComments = sql\n .split(\"\\n\")\n .filter((line) => !line.trim().startsWith(\"--\"))\n .join(\"\\n\");\n return withoutComments\n .split(\";\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n}\n\nexport interface DestructiveStatement {\n /** The offending statement (trimmed, without the trailing `;`). */\n statement: string;\n /** Which destructive operation it was flagged for, e.g. \"DROP COLUMN\". */\n kind: string;\n}\n\n/**\n * Scan an Atlas plan (the SQL printed by `schema apply --dry-run`) and return\n * the statements that would destroy data. An empty array means the plan is\n * safe to auto-approve.\n */\nexport function detectDestructiveStatements(planSql: string): DestructiveStatement[] {\n const found: DestructiveStatement[] = [];\n for (const statement of splitSqlStatements(planSql)) {\n for (const { label, re } of DESTRUCTIVE_PATTERNS) {\n if (re.test(statement)) {\n found.push({ statement, kind: label });\n break; // one label per statement is enough to flag it\n }\n }\n }\n return found;\n}\n\nexport type PushDecision = \"apply\" | \"confirm\" | \"refuse\";\n\n/**\n * Decide how `db push` should proceed given the plan's destructiveness and\n * the invocation context.\n *\n * - No destructive statements → `apply` (safe to auto-approve).\n * - Destructive + `--allow-destructive` → `apply` (operator opted in).\n * - Destructive + interactive TTY → `confirm` (prompt before applying).\n * - Destructive + non-interactive → `refuse` (never silently drop data in\n * CI / scripts / agents).\n */\nexport function decidePushSafety(opts: {\n destructiveCount: number;\n allowDestructive: boolean;\n interactive: boolean;\n}): PushDecision {\n if (opts.destructiveCount === 0) return \"apply\";\n if (opts.allowDestructive) return \"apply\";\n return opts.interactive ? \"confirm\" : \"refuse\";\n}\n","/**\n * Which columns an Atlas plan cannot touch, because a generated column reads\n * them.\n *\n * PostgreSQL refuses `ALTER COLUMN … TYPE` and `DROP COLUMN` on any column a\n * `GENERATED ALWAYS AS … STORED` expression depends on:\n *\n * cannot alter type of a column used by a generated column\n *\n * Atlas cannot see that coming. A search block's `tsvector` is *deliberately*\n * hidden from it (`searchExcludePatterns`) — Rebase owns that column, and an\n * Atlas that could see it would plan a `DROP COLUMN` for it on every push,\n * since the desired state it is given never mentions one. So Atlas plans an\n * alter against a column whose dependant is invisible to it, PostgreSQL\n * refuses, and because `schema apply` runs its plan in a single transaction\n * **every unrelated statement rolls back with it**. One `varchar(255)` → `text`\n * widening on a searched column is enough to make `rebase db push` a no-op\n * forever, with an error that names neither the generated column nor the reason.\n *\n * The fix is the same one the search column's own stamp guard already\n * prescribes when a `search` block changes: drop the generated column, let the\n * apply through, and rebuild it from `search.sql` afterwards. It is cheap to\n * rebuild (one table rewrite, which the `ALTER … TYPE` was going to cost\n * anyway) and there is no other order that works — the expression cannot be\n * altered in place at all.\n *\n * Everything here is side-effect free: the plan is text and the dependencies\n * are rows someone else read. Unit-tested in\n * `generated-column-conflicts.test.ts`.\n */\nimport { splitSqlStatements } from \"./destructive-sql\";\n\n/** An operation on a column that PostgreSQL refuses while a dependant exists. */\nexport type ColumnMutationKind = \"type\" | \"drop\";\n\nexport interface ColumnMutation {\n /** Absent when the plan did not qualify the table; matched loosely then. */\n schema?: string;\n table: string;\n column: string;\n kind: ColumnMutationKind;\n}\n\n/** One `generated column → column it reads` edge, as read from the catalogue. */\nexport interface GeneratedColumnDependency {\n schema: string;\n table: string;\n /** The generated column. */\n column: string;\n /** A column its expression reads. */\n dependsOn: string;\n}\n\n/** A generated column standing in the way of the plan, and why. */\nexport interface GeneratedColumnConflict {\n schema: string;\n table: string;\n /** The generated column that has to go before the apply. */\n column: string;\n /** The mutated columns it reads, deduplicated and sorted. */\n blocking: { column: string; kind: ColumnMutationKind }[];\n}\n\n/** `\"public\".\"posts\"` / `public.posts` / `posts` → its parts. */\nconst IDENT = String.raw`(?:\"[^\"]+\"|[A-Za-z_][A-Za-z0-9_$]*)`;\nconst TABLE_RE = new RegExp(String.raw`^ALTER\\s+TABLE\\s+(?:ONLY\\s+)?(${IDENT})(?:\\.(${IDENT}))?`, \"i\");\nconst ALTER_COLUMN_RE = new RegExp(\n String.raw`\\bALTER\\s+(?:COLUMN\\s+)?(${IDENT})\\s+(?:SET\\s+DATA\\s+)?TYPE\\b`, \"gi\"\n);\nconst DROP_COLUMN_RE = new RegExp(\n String.raw`\\bDROP\\s+COLUMN\\s+(?:IF\\s+EXISTS\\s+)?(${IDENT})`, \"gi\"\n);\n\nconst unquote = (ident: string): string =>\n ident.startsWith(\"\\\"\") ? ident.slice(1, -1) : ident;\n\n/**\n * Strip Atlas's plan rendering from a statement.\n *\n * What `schema apply --dry-run` prints is not a SQL file: each statement is\n * indented under a `-- modify \"posts\" table` heading and prefixed with `-> `,\n * with an `-- ok (12µs)` line after it. `splitSqlStatements` drops the comment\n * lines, and this drops the arrow — without it an anchored `^ALTER TABLE`\n * matches nothing at all, which is a silent no-op rather than an error.\n */\nconst stripPlanMarker = (statement: string): string =>\n statement.replace(/^\\s*->\\s*/, \"\").trim();\n\n/**\n * Every column an Atlas plan retypes or drops, with the table it belongs to.\n *\n * One statement carries many clauses — Atlas emits `ALTER TABLE \"public\".\"posts\"\n * ALTER COLUMN \"title\" TYPE text, ALTER COLUMN \"slug\" TYPE text, …` — so the\n * table is read once per statement and the clauses are scanned within it.\n */\nexport function parseColumnMutations(planSql: string): ColumnMutation[] {\n const mutations: ColumnMutation[] = [];\n\n for (const raw of splitSqlStatements(planSql)) {\n const statement = stripPlanMarker(raw);\n const table = TABLE_RE.exec(statement);\n if (!table) continue;\n // With both groups present the first is the schema; with one, the\n // statement named a bare table and the schema is whatever search_path\n // resolves to — which we cannot know here, so it stays undefined and\n // `findGeneratedColumnConflicts` matches on the table name alone.\n const [schema, name] = table[2]\n ? [unquote(table[1]), unquote(table[2])]\n : [undefined, unquote(table[1])];\n\n const collect = (re: RegExp, kind: ColumnMutationKind) => {\n re.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(statement)) !== null) {\n mutations.push({ schema, table: name, column: unquote(match[1]), kind });\n }\n };\n collect(ALTER_COLUMN_RE, \"type\");\n collect(DROP_COLUMN_RE, \"drop\");\n }\n\n return mutations;\n}\n\n/**\n * The generated columns that block a plan: those reading a column it retypes\n * or drops.\n *\n * A mutation with no schema matches on table name alone. That is deliberately\n * loose — a bare `ALTER TABLE posts` resolves through `search_path` at\n * execution time, and guessing wrong in the *permissive* direction costs a\n * generated column that is rebuilt seconds later, while guessing wrong in the\n * strict direction costs the whole push.\n */\nexport function findGeneratedColumnConflicts(\n mutations: ColumnMutation[],\n dependencies: GeneratedColumnDependency[]\n): GeneratedColumnConflict[] {\n const conflicts = new Map<string, GeneratedColumnConflict>();\n\n for (const dependency of dependencies) {\n for (const mutation of mutations) {\n if (mutation.table !== dependency.table) continue;\n if (mutation.schema !== undefined && mutation.schema !== dependency.schema) continue;\n if (mutation.column !== dependency.dependsOn) continue;\n\n const key = `${dependency.schema}.${dependency.table}.${dependency.column}`;\n const conflict = conflicts.get(key) ?? {\n schema: dependency.schema,\n table: dependency.table,\n column: dependency.column,\n blocking: []\n };\n if (!conflict.blocking.some(b => b.column === mutation.column && b.kind === mutation.kind)) {\n conflict.blocking.push({ column: mutation.column, kind: mutation.kind });\n }\n conflicts.set(key, conflict);\n }\n }\n\n const ordered = [...conflicts.values()];\n for (const conflict of ordered) conflict.blocking.sort((a, b) => a.column.localeCompare(b.column));\n return ordered.sort((a, b) => `${a.schema}.${a.table}.${a.column}`.localeCompare(`${b.schema}.${b.table}.${b.column}`));\n}\n\n/**\n * Split the conflicts into the ones Rebase can rebuild and the ones it cannot.\n *\n * `managed` is decided by the very list that hid the column from Atlas: a\n * `schema.table.column` exclude pattern means Rebase generated the column and\n * `search.sql` will put it back. Anything else is somebody's hand-written\n * generated column — dropping it would destroy a definition Rebase has no copy\n * of, so it is reported and the push stops instead.\n */\nexport function partitionByOwnership(\n conflicts: GeneratedColumnConflict[],\n excludePatterns: string[]\n): { managed: GeneratedColumnConflict[]; foreign: GeneratedColumnConflict[] } {\n const owned = new Set(excludePatterns);\n const managed: GeneratedColumnConflict[] = [];\n const foreign: GeneratedColumnConflict[] = [];\n for (const conflict of conflicts) {\n const target = `${conflict.schema}.${conflict.table}.${conflict.column}`;\n (owned.has(target) ? managed : foreign).push(conflict);\n }\n return { managed, foreign };\n}\n\n/**\n * `ALTER TABLE … DROP COLUMN …` for each conflict, in catalogue order.\n *\n * `ifExists` is for the migration path, where the statement is written now and\n * runs later against a database nobody can inspect: on a fresh one the column\n * does not exist yet (the migration is about to create the table), on a live\n * one it does, and the same file has to survive both.\n */\nexport function dropGeneratedColumnStatements(\n conflicts: GeneratedColumnConflict[],\n opts: { ifExists?: boolean } = {}\n): string[] {\n const guard = opts.ifExists ? \"IF EXISTS \" : \"\";\n return conflicts.map(c => `ALTER TABLE \"${c.schema}\".\"${c.table}\" DROP COLUMN ${guard}\"${c.column}\";`);\n}\n\n/**\n * The preamble a migration needs when it retypes a column a search block reads.\n *\n * Prepended, because the drop has to precede the `ALTER COLUMN … TYPE` that\n * PostgreSQL would otherwise refuse. The column comes back at the end of the\n * same migration: `db generate` appends `search.sql`, whose\n * `ADD COLUMN IF NOT EXISTS` rebuilds the column, its index and its stamp.\n */\nexport function migrationDropPreamble(conflicts: GeneratedColumnConflict[]): string {\n if (conflicts.length === 0) return \"\";\n const reasons = conflicts.map(c => {\n const reads = c.blocking.map(b => `${b.column} (${b.kind})`).join(\", \");\n return `-- ${describeConflict(c)} reads ${reads}`;\n });\n return [\n \"-- Rebase: generated columns removed so the statements below can run.\",\n \"-- PostgreSQL refuses to retype or drop a column while a GENERATED\",\n \"-- ALWAYS AS … STORED expression reads it.\",\n ...reasons,\n \"-- The search DDL appended at the end of this migration rebuilds them.\",\n ...dropGeneratedColumnStatements(conflicts, { ifExists: true }),\n \"\"\n ].join(\"\\n\");\n}\n\n/** `public.posts.search_vector`, the way every message here names one. */\nexport function describeConflict(conflict: GeneratedColumnConflict): string {\n return `${conflict.schema}.${conflict.table}.${conflict.column}`;\n}\n","/**\n * Keep the objects Rebase carved out of Atlas's view out of the migrations\n * Atlas writes.\n *\n * `db push` protects them with `--exclude`. `atlas migrate diff` has no such\n * flag — measured on the pinned 1.2.3, `--exclude` is rejected outright with\n * `unknown flag`, and the `exclude` attribute of an `atlas.hcl` `env` block is\n * accepted and then silently ignored on that path. So the diff sees the search\n * column that the migration directory's own appended DDL created when it\n * replayed, does not see it in `schema.sql`, and plans a drop:\n *\n * ALTER TABLE \"public\".\"talents\" DROP COLUMN \"search_vector\";\n *\n * That statement is removed here, after Atlas has written the file and before\n * anything is appended to it — so the input is always Atlas's own plain output,\n * never the dollar-quoted helper bodies that get appended afterwards.\n *\n * The drop does not arrive alone. Atlas folds every change to one table into a\n * single statement, so a real edit in the same run produces\n *\n * ALTER TABLE \"public\".\"talents\"\n * DROP COLUMN \"search_vector\", DROP COLUMN \"interests\", ADD COLUMN \"headline\" text NULL;\n *\n * and dropping the whole statement would silently throw away a migration the\n * project asked for. The removal is therefore per *clause*.\n *\n * Fail-safe throughout: a statement that mentions a carved-out object but does\n * not match a shape this understands is left exactly as it is and reported as\n * `unhandled`, so the caller can say so out loud. A spurious drop the developer\n * can see beats a migration quietly rewritten wrong.\n */\n\n/** Anything Postgres accepts in an unquoted identifier past ASCII. */\nconst IDENT = \"(?:\\\"(?:[^\\\"]|\\\"\\\")*\\\"|[A-Za-z_\\\\u0080-\\\\uffff][\\\\w$\\\\u0080-\\\\uffff]*)\";\nconst QUALIFIED = `${IDENT}(?:\\\\s*\\\\.\\\\s*${IDENT})*`;\n\nconst ALTER_TABLE_RE = new RegExp(`^ALTER\\\\s+TABLE\\\\s+(?:ONLY\\\\s+)?(${QUALIFIED})\\\\s+([\\\\s\\\\S]+)$`, \"i\");\nconst DROP_COLUMN_RE = new RegExp(`^DROP\\\\s+(?:COLUMN\\\\s+)?(?:IF\\\\s+EXISTS\\\\s+)?(${IDENT})$`, \"i\");\nconst DROP_INDEX_RE = new RegExp(`^DROP\\\\s+INDEX\\\\s+(?:CONCURRENTLY\\\\s+)?(?:IF\\\\s+EXISTS\\\\s+)?(${QUALIFIED})$`, \"i\");\n\n/**\n * Does this statement destroy anything at all?\n *\n * The gate on reporting. A statement that merely *names* a carved-out object —\n * `COMMENT ON COLUMN … \"search_vector\"` — is not a problem and must not be\n * reported as one, because an unrewritable drop stops the caller outright.\n */\nconst MENTIONS_DROP = /\\bDROP\\b/i;\n\n/** One `schema.table.object` exclude pattern, taken apart. */\nexport interface CarvedOutObject {\n schema: string;\n table: string;\n object: string;\n}\n\nexport interface StripResult {\n /** The migration text with the carved-out clauses gone. */\n sql: string;\n /** What was removed, as SQL fragments, for reporting. */\n removed: string[];\n /**\n * Statements naming a carved-out object that this could not rewrite with\n * confidence. Left untouched in `sql`.\n */\n unhandled: string[];\n /** True when nothing but comments and whitespace survives. */\n empty: boolean;\n}\n\n/**\n * Split `schema.table.object` patterns. Anything not in three parts is\n * ignored rather than guessed at — the two-part form is the one Atlas itself\n * silently mis-reads, and repeating that mistake here would be worse than\n * doing nothing.\n */\nexport function parseExcludePatterns(patterns: string[]): CarvedOutObject[] {\n const parsed: CarvedOutObject[] = [];\n for (const pattern of patterns) {\n const parts = pattern.split(\".\");\n if (parts.length !== 3) continue;\n if (parts.some((p) => p.length === 0)) continue;\n parsed.push({ schema: parts[0], table: parts[1], object: parts[2] });\n }\n return parsed;\n}\n\n/** `\"public\"` and `public` are the same name; `\"Public\"` is not `public`. */\nfunction unquoteIdentifier(raw: string): string {\n const trimmed = raw.trim();\n if (trimmed.startsWith(\"\\\"\") && trimmed.endsWith(\"\\\"\") && trimmed.length >= 2) {\n return trimmed.slice(1, -1).replace(/\"\"/g, \"\\\"\");\n }\n // An unquoted identifier is folded to lower case by Postgres.\n return trimmed.toLowerCase();\n}\n\n/** Split a dotted identifier at its top-level dots, respecting quoting. */\nfunction splitQualifiedName(raw: string): string[] | null {\n const parts: string[] = [];\n let current = \"\";\n let inQuote = false;\n for (let i = 0; i < raw.length; i++) {\n const ch = raw[i];\n if (inQuote) {\n if (ch === \"\\\"\") {\n if (raw[i + 1] === \"\\\"\") { current += \"\\\"\\\"\"; i++; continue; }\n inQuote = false;\n }\n current += ch;\n continue;\n }\n if (ch === \"\\\"\") { inQuote = true; current += ch; continue; }\n if (ch === \".\") { parts.push(current); current = \"\"; continue; }\n current += ch;\n }\n if (inQuote) return null;\n parts.push(current);\n return parts.map(unquoteIdentifier);\n}\n\n/**\n * One statement located in the source text, with the comment lines that\n * introduce it. Atlas writes `-- Modify \"talents\" table` above each statement;\n * removing the statement without its comment leaves a caption over nothing.\n */\ninterface LocatedStatement {\n /** Offset of the first character of the leading comment block. */\n start: number;\n /** Offset just past the terminating semicolon. */\n end: number;\n /** Offset of the first character of the statement itself. */\n bodyStart: number;\n /** The statement without its leading comments or trailing semicolon. */\n body: string;\n}\n\n/**\n * Walk the script and locate every statement. Quote-, comment- and\n * dollar-aware: the appended halves of a migration are not passed here, but a\n * splitter that shreds a `DO $tag$ ... $tag$` block is a trap worth not\n * leaving behind — it is how the derived-names renderer broke.\n *\n * Returns null if the text ends inside a quote or a dollar-quoted body, or\n * trails off in a statement with no semicolon. Either means this cannot be\n * reasoned about safely.\n */\nfunction locateStatements(sql: string): LocatedStatement[] | null {\n const statements: LocatedStatement[] = [];\n let i = 0;\n let statementStart = 0;\n let sawCode = false;\n\n const pushStatement = (endExclusive: number) => {\n const leading = sql.slice(statementStart, endExclusive);\n // The leading run of comment/blank lines belongs to this statement.\n let consumed = 0;\n for (const line of leading.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed === \"\" || trimmed.startsWith(\"--\")) {\n consumed += line.length + 1;\n continue;\n }\n break;\n }\n const bodyStart = statementStart + consumed;\n statements.push({\n start: statementStart,\n end: endExclusive,\n bodyStart,\n body: sql.slice(bodyStart, endExclusive).replace(/;\\s*$/, \"\").trim()\n });\n };\n\n while (i < sql.length) {\n const ch = sql[i];\n\n if (ch === \"-\" && sql[i + 1] === \"-\") {\n const nl = sql.indexOf(\"\\n\", i);\n i = nl === -1 ? sql.length : nl + 1;\n continue;\n }\n if (ch === \"/\" && sql[i + 1] === \"*\") {\n const close = sql.indexOf(\"*/\", i + 2);\n if (close === -1) return null;\n i = close + 2;\n sawCode = true;\n continue;\n }\n if (ch === \"'\" || ch === \"\\\"\") {\n const quote = ch;\n i++;\n let closed = false;\n while (i < sql.length) {\n if (sql[i] === quote) {\n if (sql[i + 1] === quote) { i += 2; continue; }\n i++;\n closed = true;\n break;\n }\n i++;\n }\n if (!closed) return null;\n sawCode = true;\n continue;\n }\n if (ch === \"$\") {\n const tag = /^\\$(?:[A-Za-z_\\u0080-\\uffff][\\w\\u0080-\\uffff]*)?\\$/.exec(sql.slice(i));\n if (tag) {\n const close = sql.indexOf(tag[0], i + tag[0].length);\n if (close === -1) return null;\n i = close + tag[0].length;\n sawCode = true;\n continue;\n }\n }\n if (ch === \";\") {\n pushStatement(i + 1);\n i++;\n statementStart = i;\n sawCode = false;\n continue;\n }\n if (!/\\s/.test(ch)) sawCode = true;\n i++;\n }\n\n // Trailing text with no semicolon: only comments and whitespace is fine.\n if (sawCode) return null;\n return statements;\n}\n\n/** Split an ALTER TABLE action list at its top-level commas. */\nfunction splitClauses(actions: string): string[] | null {\n const clauses: string[] = [];\n let depth = 0;\n let current = \"\";\n let i = 0;\n while (i < actions.length) {\n const ch = actions[i];\n if (ch === \"'\" || ch === \"\\\"\") {\n const quote = ch;\n current += ch;\n i++;\n let closed = false;\n while (i < actions.length) {\n current += actions[i];\n if (actions[i] === quote) {\n if (actions[i + 1] === quote) { current += actions[i + 1]; i += 2; continue; }\n i++;\n closed = true;\n break;\n }\n i++;\n }\n if (!closed) return null;\n continue;\n }\n if (ch === \"(\") { depth++; current += ch; i++; continue; }\n if (ch === \")\") { depth--; current += ch; i++; continue; }\n if (ch === \",\" && depth === 0) { clauses.push(current); current = \"\"; i++; continue; }\n current += ch;\n i++;\n }\n if (depth !== 0) return null;\n clauses.push(current);\n return clauses.map((c) => c.trim()).filter((c) => c.length > 0);\n}\n\n/**\n * Remove every clause and statement that would drop one of `patterns`.\n *\n * `patterns` are the `schema.table.object` strings the CLI already builds for\n * Atlas's `--exclude`, so the diff path and the apply path protect exactly the\n * same set by construction.\n */\nexport function stripCarvedOutStatements(migrationSql: string, patterns: string[]): StripResult {\n const carved = parseExcludePatterns(patterns);\n if (carved.length === 0) {\n return { sql: migrationSql, removed: [], unhandled: [], empty: isBlank(migrationSql) };\n }\n\n const located = locateStatements(migrationSql);\n if (located === null) {\n // Nothing can be trusted about the offsets, so nothing moves. Worth\n // stopping the caller over only if one of ours is being dropped in\n // there; otherwise this file has nothing to do with us.\n const atStake = MENTIONS_DROP.test(migrationSql)\n && carved.some((c) => migrationSql.includes(c.object));\n return {\n sql: migrationSql,\n removed: [],\n unhandled: atStake ? [migrationSql.trim()] : [],\n empty: isBlank(migrationSql)\n };\n }\n\n const removed: string[] = [];\n const unhandled: string[] = [];\n // Edits as [start, end) → replacement, applied back-to-front so the\n // offsets of the ones still pending stay valid.\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n for (const statement of located) {\n if (!carved.some((c) => statement.body.includes(c.object))) continue;\n\n const dropIndex = DROP_INDEX_RE.exec(statement.body);\n if (dropIndex) {\n const parts = splitQualifiedName(dropIndex[1]);\n const name = parts?.[parts.length - 1];\n const schema = parts && parts.length > 1 ? parts[parts.length - 2] : undefined;\n if (name !== undefined && carved.some((c) =>\n c.object === name && (schema === undefined || c.schema === schema))) {\n removed.push(statement.body);\n edits.push({ start: statement.start, end: statement.end, replacement: \"\" });\n } else {\n // A near-miss on the name — some other index whose name\n // contains ours. Left alone, and still a drop, so still\n // reported.\n unhandled.push(statement.body);\n }\n continue;\n }\n\n // Anything else naming a carved-out object is only our business if it\n // destroys something. `COMMENT ON COLUMN … \"search_vector\"` does not.\n const alter = ALTER_TABLE_RE.exec(statement.body);\n if (!alter) {\n if (MENTIONS_DROP.test(statement.body)) unhandled.push(statement.body);\n continue;\n }\n\n const target = splitQualifiedName(alter[1]);\n if (!target) {\n if (MENTIONS_DROP.test(statement.body)) unhandled.push(statement.body);\n continue;\n }\n const table = target[target.length - 1];\n const schema = target.length > 1 ? target[target.length - 2] : undefined;\n\n const clauses = splitClauses(alter[2]);\n if (!clauses) {\n if (MENTIONS_DROP.test(statement.body)) unhandled.push(statement.body);\n continue;\n }\n\n const survivors: string[] = [];\n let removedHere = 0;\n let unhandledHere = false;\n for (const clause of clauses) {\n const drop = DROP_COLUMN_RE.exec(clause);\n const column = drop ? unquoteIdentifier(drop[1]) : undefined;\n const isCarved = column !== undefined && carved.some((c) =>\n c.object === column &&\n c.table === table &&\n (schema === undefined || c.schema === schema));\n if (isCarved) {\n removed.push(`ALTER TABLE ${alter[1]}: ${clause}`);\n removedHere++;\n continue;\n }\n // A clause naming a carved-out object in some other shape is not\n // something to guess at — if it destroys it.\n if (MENTIONS_DROP.test(clause) && carved.some((c) => clause.includes(c.object))) {\n unhandledHere = true;\n }\n survivors.push(clause);\n }\n\n if (unhandledHere) unhandled.push(statement.body);\n if (removedHere === 0) continue;\n\n if (survivors.length === 0) {\n edits.push({ start: statement.start, end: statement.end, replacement: \"\" });\n } else {\n edits.push({\n start: statement.bodyStart,\n end: statement.end,\n replacement: `ALTER TABLE ${alter[1]} ${survivors.join(\", \")};`\n });\n }\n }\n\n let sql = migrationSql;\n for (const edit of edits.sort((a, b) => b.start - a.start)) {\n sql = sql.slice(0, edit.start) + edit.replacement + sql.slice(edit.end);\n }\n if (edits.length > 0) sql = tidy(sql);\n\n return { sql, removed, unhandled, empty: isBlank(sql) };\n}\n\n/** Only comments and whitespace left — nothing a migration would do. */\nfunction isBlank(sql: string): boolean {\n return sql\n .split(\"\\n\")\n .every((line) => line.trim() === \"\" || line.trim().startsWith(\"--\"));\n}\n\n/** Collapse the blank runs an excision leaves behind. */\nfunction tidy(sql: string): string {\n const trimmed = sql.replace(/\\n{3,}/g, \"\\n\\n\").replace(/^\\s*\\n/, \"\").trimEnd();\n return trimmed.length === 0 ? \"\" : `${trimmed}\\n`;\n}\n","/**\n * The argv `runAtlas` hands the Atlas binary, as a pure function.\n *\n * Split out of `cli.ts` because the flags an Atlas subcommand accepts are not\n * uniform and getting one wrong is fatal rather than degraded: Atlas rejects an\n * unknown flag before doing any work, so a flag on the wrong subcommand takes\n * the whole command down.\n *\n * `--exclude` is the one that bit. Of the six invocations here, exactly one\n * accepts it. The guard this replaces was `args.includes(\"apply\") ||\n * args.includes(\"diff\")`, and reading it as a *subcommand* test is the trap:\n * `migrate apply` passes `args.includes(\"apply\")` just as `schema apply` does.\n * So the flag went onto three invocations, two of which reject it, and both\n * `rebase db generate` and `rebase db migrate` exited 1 with `unknown flag:\n * --exclude` for every project declaring a `search` block.\n *\n * The domain is half the identity of an Atlas subcommand, and a guard that\n * looks only at `args` cannot tell `schema apply` from `migrate apply`.\n *\n * Nothing here touches a database or the filesystem, so the whole matrix is\n * unit-tested in `atlas-argv.test.ts`.\n */\n\nexport interface AtlasInvocation {\n /** `schema` or `migrate`. */\n domain: string;\n /** The subcommand and its own flags, e.g. `[\"diff\", \"--dir\", \"file://…\"]`. */\n args: string[];\n /** The target database, already rewritten for libpq. */\n url: string;\n /** The database Atlas plans against, already rewritten for libpq. */\n devUrl: string;\n /**\n * Everything the caller resolved for `--exclude`, in the order it should\n * appear. Dropped entirely when the subcommand does not accept the flag —\n * see {@link acceptsExcludeFlag}.\n */\n excludes?: string[];\n}\n\n/**\n * Does this Atlas invocation accept `--exclude`?\n *\n * Only `atlas schema apply` does, on the pinned 1.2.3. Measured against the\n * binary: `migrate diff` and `migrate apply` both answer `unknown flag:\n * --exclude`, and neither lists it in `--help` (`migrate apply` offers\n * `--url/--dir/--format/--revisions-schema/--dry-run/--lock-name/--lock-timeout/`\n * `--skip-lock/--baseline/--to-version/--tx-mode/--exec-order/--allow-dirty`).\n * Hence `domain === \"schema\"` and not just the subcommand.\n *\n * The `exclude` attribute of an `atlas.hcl` `env` block is not a way round it\n * either: measured, it is accepted and then ignored on the diff path, which is\n * the silent-no-match shape that costs the most time to notice.\n *\n * So the diff keeps the carved-out objects out of the migration afterwards\n * instead, with `stripCarvedOutStatements`.\n */\nexport function acceptsExcludeFlag(domain: string, args: string[]): boolean {\n return domain === \"schema\" && args.includes(\"apply\");\n}\n\n/** Assemble the full argv, connection flags and all. */\nexport function buildAtlasArgs(invocation: AtlasInvocation): string[] {\n const { domain, args, url, devUrl, excludes = [] } = invocation;\n const argv = [domain, ...args];\n\n if (domain === \"schema\") {\n if (args.includes(\"apply\")) {\n argv.push(\"--url\", url, \"--dev-url\", devUrl);\n } else if (args.includes(\"clean\") || args.includes(\"inspect\")) {\n argv.push(\"--url\", url);\n }\n } else if (domain === \"migrate\") {\n if (args.includes(\"diff\")) {\n argv.push(\"--dev-url\", devUrl);\n } else if (args.includes(\"apply\") || args.includes(\"status\")) {\n argv.push(\"--url\", url, \"--revisions-schema\", \"rebase\");\n // Measured against the pinned binary: `sql/migrate: baseline and\n // allow-dirty are mutually exclusive`. `--baseline` is the caller's\n // explicit answer to the same question `--allow-dirty` answers by\n // default, so it wins, and adding both would refuse the command.\n if (args.includes(\"apply\") && !args.includes(\"--baseline\")) {\n argv.push(\"--allow-dirty\");\n }\n }\n }\n\n // Second line of defence, deliberately not a caller's responsibility: a\n // future caller that resolves excludes for the diff path gets them dropped\n // here rather than a command that will not run.\n if (acceptsExcludeFlag(domain, args)) {\n for (const exclude of excludes) {\n argv.push(\"--exclude\", exclude);\n }\n }\n\n return argv;\n}\n","/**\n * Argument shapes for `rebase db branch`, with no dependencies.\n *\n * Its own module for the same reason `schema/atlas-argv.ts` is: `cli.ts` pulls\n * in chalk, execa and the driver runtime, so a unit test that imports it cannot\n * run. Argv parsing is the part most worth testing and the part least in need\n * of any of that.\n */\n\n/**\n * Words on a `db branch` command line that no argument accounts for.\n *\n * `rebase db branch create alpha beta` created a branch called `alpha` and\n * threw `beta` away without a word. The shapes that produces are all quiet and\n * all wrong: an unquoted name (`create my feature` → `my`), a flag written\n * without its dashes (`create feat from main` → `feat`), a shell that split\n * something you thought was one token. In each case the command succeeds and\n * the branch is not the one asked for — and branch names are the thing you\n * later type to switch, delete, or point a deploy at.\n *\n * Anything starting with `-` is left alone rather than validated. This runs on\n * every branch subcommand, including ones added later with flags this function\n * has never heard of, and rejecting an unrecognised flag here would break them\n * from a distance. The value after a flag that takes one is skipped for the\n * same reason: it is that flag's argument, not a stray word.\n *\n * @param words The command's own arguments: action, name, then the rest.\n */\nexport function unexpectedBranchArgs(words: readonly string[]): string[] {\n const extras: string[] = [];\n\n // 0 is the action (\"create\"); the first bare word after it is the name.\n //\n // Found by scanning rather than by position, which is the fix: `[\"list\",\n // \"--database-url\", \"postgres://…\"]` put a flag in slot 1, so the scan\n // started past it and read the URL as a stray word.\n let seenName = false;\n for (let index = 1; index < words.length; index += 1) {\n const word = words[index];\n if (word.startsWith(\"-\")) {\n if (TAKES_A_VALUE.has(word.split(\"=\")[0])) index += 1;\n continue;\n }\n if (!seenName) {\n seenName = true;\n continue;\n }\n extras.push(word);\n }\n\n return extras;\n}\n\n/**\n * Branch-line flags whose next word belongs to them.\n *\n * `--from` was the only one listed, and `--database-url` is the one that bit:\n * `rebase db branch list --database-url postgres://…` — which the CLI itself\n * appends when the checkout is on a branch, so `rebase.branches` is read in the\n * parent where it lives — answered `✗ Unexpected argument: postgres://…`. The\n * `=` form carries its value in the same word and needs no skip.\n */\nconst TAKES_A_VALUE = new Set([\"--from\", \"--older-than\", \"--database-url\"]);\n","/**\n * The flags each driver command takes, in one place, and the check that\n * enforces them.\n *\n * Every parser in `cli.ts` runs `arg(..., { permissive: true })`, which does not\n * mean \"be lenient\" — it means **an undeclared flag becomes a positional**. So\n * `rebase db push --alow-destructive` did not fail: the typo landed in `_`, the\n * push ran with the destructive gate still closed, and the developer read the\n * refusal as Rebase ignoring the flag they had just typed. `rebase schema\n * generate --ouput src/schema.ts` was worse — it wrote the default path and\n * said nothing, so the next build compiled a file nobody had regenerated.\n *\n * The check has to live at the entry point rather than in those parsers, and\n * that is not a detail: `db push` and `db generate` re-enter `schemaCommand`\n * and `generatePostgresDdlCommand` with the *db* line, so a strict parser\n * inside either of them would reject `--allow-destructive` on a line where it\n * is correct. One validation, once, against the spec for the command the user\n * actually named; the inner parsers keep reading an already-validated line.\n *\n * Commands with their own argument handling — `db branch` (`unexpectedBranchArgs`),\n * `db backup`, `db restore`, `db backups` — are deliberately absent: they own\n * their spec, and a second list here would be one more thing to keep in step.\n * An absent entry is \"not checked here\", never \"takes nothing\".\n */\nimport arg from \"arg\";\n\n/**\n * Flags that reach this process on a line it did not compose.\n *\n * `rebase db …` hands the driver the user's whole line: the CLI *reads*\n * `--database-url` and `--docker` to resolve the database and then relays them\n * verbatim, and `--debug` is what `bin/rebase.js` prints after every failure as\n * the thing to re-run with. Rejecting any of the three would make the driver\n * refuse commands the CLI documents.\n */\nconst RELAYED_FLAGS: arg.Spec = {\n \"--database-url\": String,\n \"--docker\": Boolean,\n \"--debug\": Boolean,\n \"--help\": Boolean,\n \"-h\": \"--help\"\n};\n\n/** Keyed by `\"<domain> <subcommand>\"`, the way the user types it. */\nexport const DRIVER_FLAG_SPECS: Record<string, arg.Spec> = {\n \"db push\": {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--dry-run\": Boolean,\n \"--allow-destructive\": Boolean,\n \"--yes\": Boolean,\n \"-y\": \"--yes\"\n },\n \"db generate\": {\n \"--collections\": String,\n \"-c\": \"--collections\"\n },\n // Bare positionals still pass through to `atlas migrate apply`, which takes\n // an optional amount; flags do not, apart from `--baseline`.\n //\n // `--baseline <version>` is the escape hatch for the normal case, not an\n // exotic one: every Rebase boot ensures the schema, so a production\n // database has the tables before its first migration ever runs, and\n // `migrate apply` then dies on `type \"…\" already exists (42710)`. It maps\n // onto Atlas's own `migrate apply --baseline`, which writes the revision\n // row Atlas reads — no ledger of ours.\n \"db migrate\": {\n \"--baseline\": String\n },\n \"schema generate\": {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--output\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"--watch\": Boolean,\n \"-w\": \"--watch\"\n },\n \"schema introspect\": {\n \"--output\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--force\": Boolean,\n \"-f\": \"--force\",\n \"--schema\": String\n },\n \"schema stale\": {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--output\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"--fix\": Boolean\n }\n};\n\n/**\n * One destination flag, two spellings, everywhere.\n *\n * `--out` is the primary on `rebase build`, an alias on `generate-sdk`, `db\n * backup` and `cloud env pull`, and was refused outright by the three `schema`\n * commands — so the spelling a user learned on one command was an\n * \"unknown or unexpected option\" on the next. Neither name can be retired (both\n * are shipped), so both are accepted, and {@link assertOutputAliasesPaired}\n * makes that the rule rather than a habit.\n */\nexport const OUTPUT_FLAG_ALIASES = [\"--out\", \"--output\"] as const;\n\n/**\n * Every spec that names one of the pair names both.\n *\n * Exported so the CLI's own specs can be held to it too: the drift this fixes\n * ran across two packages, and a check that only reads this file would let the\n * next `--out`-only command through.\n */\nexport function assertOutputAliasesPaired(specs: Record<string, arg.Spec>): string[] {\n const problems: string[] = [];\n for (const [command, spec] of Object.entries(specs)) {\n const present = OUTPUT_FLAG_ALIASES.filter(flag => flag in spec);\n if (present.length === 0 || present.length === OUTPUT_FLAG_ALIASES.length) continue;\n const missing = OUTPUT_FLAG_ALIASES.filter(flag => !(flag in spec));\n problems.push(`\\`${command}\\` takes ${present.join(\", \")} but not ${missing.join(\", \")}`);\n }\n return problems;\n}\n\n/**\n * The `--collections` path the user typed, or `null` if they typed none.\n *\n * Read once, at the entry point, because every command that takes it re-enters\n * the generators with the same line and each of them resolved it again — which\n * is how \"Collections path not found\" came to be printed four times before the\n * real output, and how a path that does not exist got as far as *writing* an\n * empty schema.\n *\n * Permissive, and it has to be: {@link assertKnownFlags} has already judged the\n * line, and `db push` carries flags the `--collections` spec does not name.\n */\nexport function collectionsPathIn(args: string[]): string | null {\n try {\n const parsed = arg(\n { \"--collections\": String, \"-c\": \"--collections\" },\n { argv: args.slice(2), permissive: true }\n );\n\n return parsed[\"--collections\"] ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * The long flags a `--help` usage line documents.\n *\n * `\"rebase db push [--collections <dir>] [--dry-run] …\"` → `[\"--collections\",\n * \"--dry-run\"]`. Placeholders (`<dir>`) and the alternation inside a positional\n * (`<create|list|switch>`) are not flags and are not returned.\n */\nexport function flagsInUsage(usage: string): string[] {\n return [...new Set(usage.match(/--[a-z][a-z0-9-]*/g) ?? [])];\n}\n\n/**\n * Every flag the help documents is accepted, and every flag accepted is documented.\n *\n * The drift this catches shipped: `rebase db push --help` has printed\n * `[--dry-run]` since the flag was written, `DRIVER_FLAG_SPECS[\"db push\"]` never\n * listed it, and {@link assertKnownFlags} — added later to stop typos being\n * swallowed — turned the documented flag into `unknown or unexpected option`.\n * The only way to see a push's SQL was to trip the destructive gate, which is\n * the exact problem `--dry-run` was written to solve. Worse in a project on an\n * older driver, whose permissive parser *applied* the schema on that line.\n *\n * Two hand-maintained lists in two packages cannot be kept in step by care, so\n * they are held to each other instead: `usages` is keyed the way\n * {@link DRIVER_FLAG_SPECS} is (`\"db push\"`), and comes from the CLI's own help\n * pages. A key in only one of the two is not this function's business — the\n * help covers commands that parse their own lines (`db branch`, `db backup`),\n * and an absent spec entry means \"not checked here\".\n *\n * Aliases (`\"-c\": \"--collections\"`, `\"--out\": \"--output\"`) need no line of their\n * own: they are spellings of a documented flag. Neither do {@link RELAYED_FLAGS},\n * which every driver command accepts because the CLI relays them.\n */\nexport function assertSpecMatchesUsage(\n specs: Record<string, arg.Spec>,\n usages: Record<string, string>\n): string[] {\n const problems: string[] = [];\n for (const [command, spec] of Object.entries(specs)) {\n const usage = usages[command];\n if (usage === undefined) continue;\n\n const documented = flagsInUsage(usage);\n const accepted = Object.entries(spec);\n // An alias resolves to the flag it spells; only the target needs a line.\n const canonical = new Set(\n accepted\n .map(([flag, kind]) => (typeof kind === \"string\" ? kind : flag))\n .filter(flag => flag.startsWith(\"--\"))\n );\n\n for (const flag of documented) {\n if (flag in spec || flag in RELAYED_FLAGS) continue;\n problems.push(`\\`${command}\\` documents ${flag} in its usage line but the spec rejects it`);\n }\n for (const flag of canonical) {\n if (documented.includes(flag) || flag in RELAYED_FLAGS) continue;\n problems.push(`\\`${command}\\` accepts ${flag} but no usage line documents it`);\n }\n }\n return problems;\n}\n\n/**\n * Reject a flag the named command does not take.\n *\n * `args` is the driver's whole line — `[\"db\", \"push\", …]` — so the flags are\n * read from `args.slice(2)`, past the two command words.\n *\n * Throws rather than exiting: `runPluginCommand`'s caller already turns a\n * thrown error into one red line and exit 1, and a thrown error is what the\n * tests can see.\n */\nexport function assertKnownFlags(domain: string, subcommand: string | undefined, args: string[]): void {\n if (!subcommand) return;\n const spec = DRIVER_FLAG_SPECS[`${domain} ${subcommand}`];\n if (!spec) return;\n\n try {\n arg({ ...RELAYED_FLAGS, ...spec }, { argv: args.slice(2) });\n } catch (err) {\n if (err instanceof Error && (err as arg.ArgError).code === \"ARG_UNKNOWN_OPTION\") {\n throw new Error(\n `${err.message} — run \\`rebase ${domain} --help\\` for the options ` +\n `\\`${domain} ${subcommand}\\` takes.`\n );\n }\n throw err;\n }\n}\n","/**\n * `--collections <dir>`, checked once, before anything is written.\n *\n * A path that does not resolve used to warn and carry on. Four times over —\n * `schemaCommand`, `generatePostgresDdlCommand` and the Atlas argv assembly\n * each re-enter the loader with the same line — and then both generators wrote\n * an *empty* schema: `drizzle/schema.sql` truncated to `CREATE SCHEMA IF NOT\n * EXISTS \"rebase\";`, `src/schema.generated.ts` to ten lines. Both are committed\n * artifacts. The push that followed planned a `DROP TABLE` for every table in\n * the database, and the only thing between a typo and that was the destructive\n * gate.\n *\n * The check has to be here rather than inside `loadCollectionsForCli`, which is\n * deliberately forgiving: its callers use it to narrow what Atlas may touch,\n * and making a broken *file* fatal there would block a push over something\n * unrelated. \"Does the directory the user named exist\" is a different question,\n * it was answerable before the first write, and the code already knew.\n */\nimport fs from \"fs\";\nimport path from \"path\";\nimport chalk from \"chalk\";\nimport { outError } from \"./cli-output\";\n\n/**\n * Thrown rather than exited, so the tests can see it and the entry point owns\n * the exit code.\n *\n * `alreadyReported` is read by `reportCommandFailure`: the full diagnosis is on\n * stderr by the time this is thrown, and the point of the whole change is that\n * it is printed once.\n */\nexport class CollectionsPathMissing extends Error {\n readonly alreadyReported = true;\n\n constructor(readonly typed: string, readonly resolved: string) {\n super(`Collections path not found: \"${typed}\"`);\n this.name = \"CollectionsPathMissing\";\n }\n}\n\n/**\n * The whole message, in one place, because it is printed by two callers.\n *\n * Names what was typed, what it resolved to, and the working directory it\n * resolved against — a relative `--collections` is resolved against the cwd,\n * and the generated npm script runs with `cwd: backend/`, so \"the path is\n * right and the directory is wrong\" is the commonest way to arrive here.\n */\nexport function describeMissingCollectionsPath(typed: string, resolved: string): string {\n return [\n chalk.red(`✗ Collections path not found: \"${typed}\"`),\n chalk.gray(` Resolved to: ${resolved}`),\n chalk.gray(` (relative to cwd: ${process.cwd()})`),\n \"\",\n chalk.gray(\" Nothing was generated and nothing was applied — a schema generated from a\"),\n chalk.gray(\" directory that is not there is an empty one, and applying it would drop\"),\n chalk.gray(\" every table it does not describe.\"),\n \"\",\n chalk.gray(\" Pass an absolute path, or one relative to where you run the command.\")\n ].join(\"\\n\");\n}\n\n/**\n * Refuse a `--collections` path that does not exist.\n *\n * `null` means the flag was not given: the default (`../config/collections`) is\n * left to the loader, which warns and continues — a project may legitimately\n * have no collections directory, and a headless scaffold does.\n */\nexport function assertCollectionsPathExists(typed: string | null): void {\n if (typed === null) return;\n\n const resolved = path.resolve(process.cwd(), typed);\n if (fs.existsSync(resolved)) return;\n\n outError(\"\");\n outError(describeMissingCollectionsPath(typed, resolved));\n outError(\"\");\n throw new CollectionsPathMissing(typed, resolved);\n}\n","/**\n * Which of the two things `rebase db backup …` means.\n *\n * The cloud family spells the listing `rebase cloud db backup list`. Locally\n * the same words *created a backup*: `backup` dispatched straight to\n * `backupCommand`, which parsed permissively and dropped \"list\" into the\n * positionals it never reads. One CLI, two spellings, and the wrong guess wrote\n * a dump instead of reading one — quiet, slow, and on a large database not\n * free.\n *\n * A separate module for the same reason `branch-argv.ts` is one: the decision\n * is pure, and the dispatch it lives in cannot be imported without loading the\n * environment and reaching for a database.\n */\nexport type BackupAction = \"create\" | \"list\";\n\n/**\n * @param rawArgs the driver's whole line, `[\"db\", \"backup\", …]`.\n */\nexport function backupActionOf(rawArgs: readonly string[]): BackupAction {\n return rawArgs[2] === \"list\" ? \"list\" : \"create\";\n}\n","/**\n * What `rebase db branch prune` should remove, decided without a database.\n *\n * Branching had no cleanup story at all: no TTL, no prune, no `delete --all`,\n * and every branch is a **full-size copy** — `CREATE DATABASE ... TEMPLATE`\n * duplicates the files on disk, so five branches of a 100 GB database cost\n * 500 GB. The only way to reclaim any of it was to remember every name you had\n * ever typed.\n *\n * Three things drift apart, and they are not the same problem:\n *\n * 1. **Stale rows** — `rebase.branches` says a branch exists and its database\n * is gone. Someone dropped it with plain SQL, or restored the cluster from\n * a backup taken before it. The row is what `list` reads, so the branch goes\n * on being reported forever; `switch` and `info` then fail against a\n * database nothing can find.\n *\n * 2. **Orphan databases** — an `rb_*` database with no row. `createBranch`\n * creates the database first and records it second, so a crash between the\n * two leaves exactly this: disk consumed by something no Rebase command will\n * ever mention again.\n *\n * 3. **Expired branches** — alive, registered, and older than you meant to keep.\n * This is the ordinary case and the reason the command exists.\n *\n * Atlas's scratch databases are reported alongside but never removed by\n * default. `rebase db push` creates `<db>_dev_diff` to compute its diff against\n * and does not always clean it up, so they accumulate next to the branches and\n * look like them. They are not branches, and one may belong to an Atlas run\n * happening right now — so this names them and leaves the decision to a flag.\n */\n\n/** A branch as `rebase.branches` records it. */\nexport interface BranchRow {\n name: string;\n dbName: string;\n createdAt: Date;\n}\n\nexport interface PrunePlan {\n /** Registered, but the database is gone. Remove the row only. */\n staleRows: BranchRow[];\n /** An `rb_*` database with no row. Drop the database only. */\n orphanDatabases: string[];\n /** Alive, registered, older than the cutoff. Drop both. */\n expired: { branch: BranchRow; ageDays: number }[];\n /** Atlas scratch databases. Reported; removed only when asked. */\n devDiff: string[];\n}\n\n/** True when nothing at all needs doing. */\nexport function planIsEmpty(plan: PrunePlan, includeDevDiff: boolean): boolean {\n return plan.staleRows.length === 0\n && plan.orphanDatabases.length === 0\n && plan.expired.length === 0\n && (!includeDevDiff || plan.devDiff.length === 0);\n}\n\n/**\n * Age in whole days, floored.\n *\n * Floored rather than rounded so `--older-than 7` never catches something six\n * and a half days old: a prune that removes more than it said it would is worse\n * than one that waits another twelve hours.\n */\nexport function ageInDays(createdAt: Date, now: Date): number {\n return Math.floor((now.getTime() - createdAt.getTime()) / 86_400_000);\n}\n\n/**\n * Parse `--older-than`. Accepts a bare number of days, or `7d` / `2w`.\n *\n * Returns null for anything else, so the caller refuses rather than guessing —\n * silently reading `--older-than 7h` as seven *days* would delete a week of\n * work.\n */\nexport function parseOlderThan(value: string): number | null {\n const match = /^(\\d+)\\s*([dw])?$/i.exec(value.trim());\n if (!match) return null;\n\n const amount = Number(match[1]);\n if (!Number.isFinite(amount)) return null;\n\n return match[2]?.toLowerCase() === \"w\" ? amount * 7 : amount;\n}\n\nexport function planPrune(\n input: {\n rows: readonly BranchRow[];\n /** Every database name on the server. */\n databases: readonly string[];\n branchPrefix: string;\n },\n options: { olderThanDays?: number | null; now?: Date } = {}\n): PrunePlan {\n const now = options.now ?? new Date();\n const present = new Set(input.databases);\n const registered = new Set(input.rows.map((row) => row.dbName));\n\n const staleRows = input.rows.filter((row) => !present.has(row.dbName));\n\n const orphanDatabases = input.databases\n .filter((name) => name.startsWith(input.branchPrefix) && !registered.has(name))\n .sort();\n\n const expired = options.olderThanDays == null\n ? []\n : input.rows\n // A row whose database is already gone is a stale row, not an\n // expired branch — listing it under both would offer to drop a\n // database that does not exist.\n .filter((row) => present.has(row.dbName))\n .map((branch) => ({ branch, ageDays: ageInDays(branch.createdAt, now) }))\n .filter((entry) => entry.ageDays >= options.olderThanDays!)\n .sort((a, b) => b.ageDays - a.ageDays);\n\n const devDiff = input.databases.filter((name) => name.endsWith(\"_dev_diff\")).sort();\n\n return { staleRows, orphanDatabases, expired, devDiff };\n}\n","import arg from \"arg\";\nimport chalk from \"chalk\";\nimport { execa } from \"execa\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport { fileURLToPath } from \"url\";\nimport { logger } from \"@rebasepro/server\";\nimport { out, outWarn, outError } from \"./cli-output\";\nimport { formatRelativeTime } from \"@rebasepro/utils\";\nimport {\n diagnoseMissingBin,\n detectProjectPackageManager,\n describeBuildScriptRemedy,\n describeDevAddCommand,\n describeReinstallCommand,\n resolveLocalBin,\n getTableIncludes,\n getDevDatabaseUrl,\n ensureDevDatabaseExists,\n dropDevDatabase,\n applySearchDdl,\n getSearchExcludes,\n readSearchDdl,\n applyVectorDdl,\n getVectorExcludes,\n readVectorDdl,\n applyTriggersDdl,\n getTriggerExcludes,\n readTriggersDdl,\n getTableExcludes,\n getForeignIndexExcludes,\n ExcludeIntrospectionError,\n promptConfirm,\n queryGeneratedColumnDependencies,\n dropGeneratedColumns,\n loadCollectionsForCli\n} from \"./cli-helpers\";\nimport {\n checkDatabaseConnectivity,\n diagnoseAtlasFailure,\n diagnoseDbError,\n formatForeignGeneratedColumnBanner,\n reportCommandFailure\n} from \"./cli-errors\";\nimport { forLibpq } from \"./utils/connection-string\";\nimport { dropLegacyAuthSchema, RLS_BOOTSTRAP_SQL } from \"./schema/rls-bootstrap-sql\";\nimport { detectDestructiveStatements, decidePushSafety } from \"./schema/destructive-sql\";\nimport {\n parseColumnMutations,\n findGeneratedColumnConflicts,\n partitionByOwnership,\n dropGeneratedColumnStatements,\n migrationDropPreamble,\n describeConflict\n} from \"./schema/generated-column-conflicts\";\nimport { stripCarvedOutStatements } from \"./schema/carved-out-migration\";\nimport { acceptsExcludeFlag, buildAtlasArgs } from \"./schema/atlas-argv\";\nimport { unexpectedBranchArgs } from \"./branch-argv\";\nimport { assertKnownFlags, collectionsPathIn } from \"./cli-flags\";\nimport { assertCollectionsPathExists } from \"./cli-collections-path\";\nimport { backupActionOf } from \"./backup-argv\";\n\nimport { planIsEmpty, planPrune, parseOlderThan } from \"./branch-prune\";\n\nconst __cliDirname = path.dirname(fileURLToPath(import.meta.url));\n\n/**\n * A script this CLI spawns, and how to run it.\n *\n * Four commands — `schema generate`, the DDL plan, `introspect` and the schema\n * doctor — run as child processes, located by path relative to this file. That\n * path used to be `<dir>/schema/<name>.ts`, which worked only because `files`\n * shipped `src`. When the tarball stopped shipping `src`, every one of those\n * commands broke for every npm consumer at once: the file was simply absent,\n * and the parent CLI reported the absence as \"Dependencies are not installed\"\n * at projects that had installed perfectly. 0.18.0 shipped that way — a\n * scaffolded project's first `rebase dev` could not regenerate its schema and\n * every `GET /api/data/*` answered `Table not found for collection 'posts'`.\n *\n * The build emits each of them beside this file, so a published copy carries\n * the command surface as an artifact. Source still wins where there is no\n * build, which is how the monorepo runs before `pnpm build`.\n *\n * **The interpreter is tsx either way, and that is not incidental.** These\n * scripts load the *project's* collection files, which are TypeScript and\n * import each other as `./authors.js` — the extension TypeScript tells you to\n * write. Node resolves that literally and fails on a file that does not exist;\n * tsx maps it back. Running the built `.js` under plain `node` therefore fails\n * on the user's code rather than on ours, one directory further from anything\n * the error mentions.\n */\nfunction resolveChildScript(name: string):\n | { ok: true; bin: string; script: string }\n | { ok: false; reason: \"script\" | \"tsx\" } {\n const built = path.join(__cliDirname, \"schema\", `${name}.js`);\n const source = path.join(__cliDirname, \"schema\", `${name}.ts`);\n const script = fs.existsSync(built) ? built : fs.existsSync(source) ? source : null;\n if (!script) return { ok: false, reason: \"script\" };\n\n const tsxBin = resolveLocalBin(\"tsx\");\n if (!tsxBin) return { ok: false, reason: \"tsx\" };\n\n return { ok: true, bin: tsxBin, script };\n}\n\n/** What to print when {@link resolveChildScript} cannot produce a command. */\nfunction childScriptError(what: string, reason: \"script\" | \"tsx\"): string {\n if (reason === \"tsx\") {\n return `✗ Could not find the tsx binary, which ${what} needs to read your collection files. `\n + \"Install your project's dependencies and try again.\";\n }\n return `✗ The driver's ${what} is missing. This copy of @rebasepro/server-postgres is `\n + \"incomplete — reinstall it, or run its build if you are working in the monorepo.\";\n}\n\n\n\nasync function loadEnv(): Promise<void> {\n try {\n const dotenv = await import(\"dotenv\");\n const envPaths = [\n process.env.DOTENV_CONFIG_PATH,\n path.resolve(process.cwd(), \".env\"),\n path.resolve(process.cwd(), \"../.env\"),\n path.resolve(process.cwd(), \"../../.env\")\n ].filter(Boolean) as string[];\n\n for (const p of envPaths) {\n if (fs.existsSync(p)) {\n const parsed = dotenv.config({ path: p, quiet: true });\n if (parsed.parsed) {\n for (const [key, val] of Object.entries(parsed.parsed)) {\n if (process.env[key] === undefined) {\n process.env[key] = val;\n }\n }\n break;\n }\n }\n }\n } catch {\n // ignore\n }\n}\n\nexport async function runPluginCommand(args: string[]) {\n // Also set as an environment variable, not just per `config()` call: this\n // command spawns `tsx` subprocesses (the schema generator, the DDL\n // generator, doctor) that load `.env` themselves, and they inherit this.\n // dotenv reads it before `options.quiet`; an explicit `false` still wins.\n if (process.env.DOTENV_CONFIG_QUIET === undefined) {\n process.env.DOTENV_CONFIG_QUIET = \"true\";\n }\n await loadEnv();\n const domain = args[0]; // \"db\" or \"schema\"\n const subcommand = args[1];\n\n // Before anything reads the line: every parser below runs `permissive`,\n // which turns an undeclared flag into a positional rather than an error, so\n // `db push --alow-destructive` pushed with the destructive gate still shut\n // and `schema generate --ouput x` wrote the default path in silence. See\n // cli-flags.ts for why the check has to be here and not in those parsers.\n assertKnownFlags(domain, subcommand, args);\n\n // And before anything is generated: a `--collections` path that does not\n // resolve used to warn and carry on, four times over, and the generators\n // then wrote an *empty* schema over `drizzle/schema.sql` and\n // `src/schema.generated.ts` — both committed artifacts — after which the\n // push planned a DROP TABLE for every table in the database. Only the\n // destructive gate stood between a typo and the whole schema.\n //\n // Checked here rather than in `loadCollectionsForCli`, which is\n // deliberately forgiving: its callers use it to *narrow* what Atlas may\n // touch, and a hard failure there would block a push over one broken file.\n // This is a different question — \"does the directory the user named\n // exist\" — and the answer was already known before the first write.\n assertCollectionsPathExists(collectionsPathIn(args));\n\n if (domain === \"db\") {\n await dbCommand(subcommand, args);\n } else if (domain === \"schema\") {\n await schemaCommand(subcommand, args);\n } else if (domain === \"doctor\") {\n await doctorPluginCommand(args);\n } else {\n outError(chalk.red(`Unknown domain command: ${domain}`));\n process.exit(1);\n }\n}\n\n/** The migration files on disk, sorted, or none if the directory is absent. */\nfunction listMigrationFiles(): string[] {\n const dir = path.resolve(process.cwd(), \"drizzle\", \"migrations\");\n if (!fs.existsSync(dir)) return [];\n return fs.readdirSync(dir).filter(f => f.endsWith(\".sql\")).sort();\n}\n\n/**\n * The newest migration's version — the numeric prefix Atlas records.\n *\n * `20260906101530_init.sql` → `20260906101530`. Named in the baseline remedy so\n * the command it prints can be typed rather than worked out.\n */\nfunction latestMigrationVersion(): string | null {\n const newest = listMigrationFiles().at(-1);\n if (!newest) return null;\n const match = /^(\\d+)/.exec(newest);\n return match ? match[1] : newest.replace(/\\.sql$/, \"\");\n}\n\n/**\n * Take Atlas's carve-outs back out of the migration `migrate diff` just wrote.\n *\n * The apply path hands Atlas `--exclude` and it never sees the search or vector\n * columns. The diff path has no such flag — `atlas migrate diff` rejects\n * `--exclude` outright, and an `atlas.hcl` `env` block's `exclude` is accepted\n * and then ignored — so Atlas replays the migration directory (which builds\n * both columns, because that DDL is appended to migrations), does not find them\n * in `schema.sql`, and plans `DROP COLUMN`. Applied, that would take search and\n * the embeddings away from every database the migration reaches.\n *\n * Returns whether a migration Atlas just wrote is still there afterwards: a\n * file whose only content was the spurious drop is deleted, because an empty\n * migration is worse than none — it takes a slot in the revision history and\n * the caller would append the carved-out DDL and the policies to it.\n *\n * @returns true when a new migration survives and may be appended to.\n */\nasync function stripCarvedOutFromNewestMigration(collectionsPath: string): Promise<boolean> {\n // Both carve-outs, for one reason: they are the same problem. Search is out\n // of Atlas's sight because its free tier will not parse a function; vector\n // is out because Atlas resolves the desired state in a dev database that\n // can never have pgvector. What follows from that is identical — the diff\n // replays a migration directory holding objects `schema.sql` omits, and\n // plans a drop for every one.\n const patterns = [\n ...await getSearchExcludes(collectionsPath),\n ...await getVectorExcludes(collectionsPath),\n ...await getTriggerExcludes(collectionsPath)\n ];\n if (patterns.length === 0) return true;\n\n const newest = listMigrationFiles().at(-1);\n if (!newest) return false;\n const file = path.resolve(process.cwd(), \"drizzle\", \"migrations\", newest);\n\n const result = stripCarvedOutStatements(fs.readFileSync(file, \"utf-8\"), patterns);\n\n // Fail CLOSED, and loudly. A drop this could not rewrite stays in the file\n // exactly as Atlas wrote it, and the file is one somebody applies next week\n // — by which time the column is gone and nothing connects it to this run.\n // The destructive gate does not cover it either: that reads the *push*\n // plan. So `db generate` stops here rather than hand back a migration that\n // destroys a column the developer never asked to lose.\n if (result.unhandled.length > 0) {\n outError(chalk.red(\n `\\n ✗ ${newest} drops an object Rebase manages outside Atlas, in a form the CLI`\n ));\n outError(chalk.red(\" could not remove:\"));\n for (const statement of result.unhandled) {\n outError(chalk.gray(` ${statement.replace(/\\s+/g, \" \")}`));\n }\n outError(chalk.gray(\n \" Left as Atlas wrote it. Delete those statements by hand before running\\n\" +\n \" `rebase db migrate` — and please report them: rewriting this is meant to\\n\" +\n \" be automatic.\"\n ));\n process.exit(1);\n }\n\n if (result.removed.length === 0) return true;\n\n if (result.empty) {\n fs.rmSync(file);\n out(chalk.gray(\n ` ✓ Dropped ${newest} — it planned nothing but the removal of columns\\n` +\n \" Atlas cannot see and Rebase applies itself.\"\n ));\n } else {\n fs.writeFileSync(file, result.sql, \"utf-8\");\n out(chalk.gray(` ✓ Kept Rebase's own columns out of ${newest} (${result.removed.length} statement(s))`));\n }\n\n await runAtlas(\"migrate\", [\"hash\", \"--dir\", \"file://drizzle/migrations\"], collectionsPath);\n return !result.empty;\n}\n\nasync function dbCommand(subcommand: string, rawArgs: string[]): Promise<void> {\n const VALID_ACTIONS = [\"push\", \"generate\", \"migrate\", \"branch\", \"backup\", \"restore\", \"backups\"];\n if (!subcommand || !VALID_ACTIONS.includes(subcommand)) {\n outError(chalk.red(`Unknown db command. Valid: ${VALID_ACTIONS.join(\", \")}`));\n process.exit(1);\n }\n\n // A second line of defence, and not a redundant one. `rebase db` answers\n // `--help` before it ever spawns this file, but this file is also its own\n // CLI — the driver is spawned directly by `resolvePluginCliScript`, and is\n // executable on its own — so a `--help` reaching here means nobody upstream\n // caught it. Only `branch` had a case for it; `push`, `migrate` and\n // `restore` all took `--help` as an ordinary flag and did the work.\n if (rawArgs.includes(\"--help\") || rawArgs.includes(\"-h\")) {\n out(\"\");\n out(chalk.bold(` rebase db ${subcommand}`));\n out(chalk.gray(\" Run `rebase db --help` for the full page — this is the driver's own entry point.\"));\n out(\"\");\n return;\n }\n\n if (subcommand === \"branch\") {\n await branchCommand(rawArgs);\n return;\n }\n\n if (subcommand === \"backup\" || subcommand === \"restore\" || subcommand === \"backups\") {\n const { backupCommand, restoreCommand, backupsCommand } = await import(\"./backup/backup-cli\");\n // `rebase cloud db backup list` is how the cloud family spells this, and\n // locally the same words *created a backup*: \"list\" was a positional\n // `backupCommand` ignored. One CLI, two spellings, and the wrong guess\n // wrote a dump instead of reading one. Both spellings list now.\n if (subcommand === \"backup\" && backupActionOf(rawArgs) === \"list\") await backupsCommand(rawArgs);\n else if (subcommand === \"backup\") await backupCommand(rawArgs);\n else if (subcommand === \"restore\") await restoreCommand(rawArgs);\n else await backupsCommand(rawArgs);\n return;\n }\n\n const argsList = arg(\n {\n \"--collections\": String,\n \"--allow-destructive\": Boolean,\n \"--dry-run\": Boolean,\n \"--yes\": Boolean,\n \"--baseline\": String,\n \"-c\": \"--collections\",\n \"-y\": \"--yes\"\n },\n {\n argv: rawArgs.slice(2),\n permissive: true\n }\n );\n const collectionsPath = argsList[\"--collections\"] || path.join(\"..\", \"config\", \"collections\");\n\n if (subcommand === \"generate\") {\n out(\"\");\n out(chalk.bold(\" 📦 Rebase DB Generate\"));\n out(chalk.gray(\" Step 1/2: Generating Drizzle schema & Postgres DDL from collections...\"));\n out(\"\");\n await schemaCommand(\"generate\", rawArgs);\n await generatePostgresDdlCommand(rawArgs);\n out(\"\");\n out(chalk.gray(\" Step 2/2: Generating SQL migration files with Atlas...\"));\n out(\"\");\n const migrationName = argsList._[0] || \"migration\";\n const migrationsBefore = listMigrationFiles();\n await runAtlas(\"migrate\", [\"diff\", migrationName, \"--dir\", \"file://drizzle/migrations\", \"--to\", \"file://drizzle/schema.sql\"], collectionsPath);\n // The diff cannot be told to ignore the carved-out objects the way the\n // apply can, so the drop it plans for them is taken back out of the\n // file it just wrote. A migration that was nothing else is deleted.\n let wroteNewMigration = listMigrationFiles().length > migrationsBefore.length;\n if (wroteNewMigration) {\n wroteNewMigration = await stripCarvedOutFromNewestMigration(collectionsPath);\n }\n \n // Post-process the migration Atlas just wrote.\n //\n // `wroteNewMigration` gates the whole block, and that gate is the point.\n // \"The newest migration file\" is only Atlas's when Atlas wrote one;\n // otherwise it is a migration that has already run in production, and\n // appending to it changes a hash Atlas has recorded while the appended\n // SQL never runs anywhere. The search half already said so and checked;\n // the `CREATE SCHEMA` rewrite and the policy append did not, so every\n // `db generate` that found nothing to diff still grew the last\n // migration by another copy of the policies.\n try {\n const migrationsDir = path.resolve(process.cwd(), \"drizzle\", \"migrations\");\n if (fs.existsSync(migrationsDir) && wroteNewMigration) {\n const files = fs.readdirSync(migrationsDir);\n const sqlFiles = files\n .filter(f => f.endsWith(\".sql\"))\n .sort();\n if (sqlFiles.length > 0) {\n const newestMigrationFile = path.join(migrationsDir, sqlFiles[sqlFiles.length - 1]);\n\n // Make CREATE SCHEMA idempotent so it doesn't conflict with\n // --revisions-schema (Atlas pre-creates the rebase schema\n // for its revision table before running migrations).\n let migrationContent = fs.readFileSync(newestMigrationFile, \"utf-8\");\n migrationContent = migrationContent.replace(\n /CREATE SCHEMA (?!IF NOT EXISTS)(\"[^\"]+\");/g,\n \"CREATE SCHEMA IF NOT EXISTS $1;\"\n );\n // Atlas never writes the search or vector objects into a\n // migration — it is not shown them — so a migration\n // replayed against a fresh database would build every table\n // except the parts that make search and vector search work.\n // Appending, because these are `ALTER TABLE ... ADD COLUMN`\n // over the tables the migration just created.\n //\n // Vector first: `vector.sql` may open with\n // `CREATE EXTENSION vector`, so prerequisites lead, which is\n // the order a reader of the migration expects. Nothing in\n // search depends on it either way.\n const vectorContent = readVectorDdl();\n if (vectorContent) {\n migrationContent = `${migrationContent}\\n\\n${vectorContent}`;\n out(chalk.gray(\" ✓ Appended vector DDL to the migration\"));\n }\n\n const searchContent = readSearchDdl();\n if (searchContent) {\n // The same refusal `db push` works around, but decided\n // here and written into the file: this migration runs\n // later, somewhere else, against a database nobody can\n // inspect from this machine. A column retyped by the\n // statements above cannot be retyped while the search\n // column reads it, and the appended DDL below runs too\n // late to help — so the drop is prepended and the\n // rebuild is the append that was already happening.\n //\n // Derived from the collections rather than a catalogue:\n // `searchColumnDependencies` knows which columns each\n // block reads, which is all the decision needs.\n const { searchColumnDependencies } = await import(\"./schema/generate-postgres-ddl-logic\");\n const migrationConflicts = findGeneratedColumnConflicts(\n parseColumnMutations(migrationContent),\n searchColumnDependencies(await loadCollectionsForCli(collectionsPath))\n );\n const preamble = migrationDropPreamble(migrationConflicts);\n if (preamble) {\n migrationContent = `${preamble}\\n${migrationContent}`;\n for (const conflict of migrationConflicts) {\n out(chalk.gray(` ✓ ${describeConflict(conflict)} is dropped and rebuilt inside the migration`));\n }\n }\n migrationContent = `${migrationContent}\\n\\n${searchContent}`;\n out(chalk.gray(\" ✓ Appended search DDL to the migration\"));\n }\n\n // Last of the three: a trigger needs its table and its\n // column, and both arrive above.\n const triggersContent = readTriggersDdl();\n if (triggersContent) {\n migrationContent = `${migrationContent}\\n\\n${triggersContent}`;\n out(chalk.gray(\" ✓ Appended `updated_at` triggers to the migration\"));\n }\n\n fs.writeFileSync(newestMigrationFile, migrationContent, \"utf-8\");\n\n // Append RLS policies, preceded by the RLS bootstrap so the\n // migration is self-contained: Atlas replays migrations\n // against a clean dev database where `rebase.uid()` would\n // not otherwise exist.\n const policiesFile = path.resolve(process.cwd(), \"drizzle\", \"policies.sql\");\n if (fs.existsSync(policiesFile)) {\n const policiesContent = fs.readFileSync(policiesFile, \"utf-8\");\n fs.appendFileSync(newestMigrationFile, \"\\n\\n\" + RLS_BOOTSTRAP_SQL + \"\\n\" + policiesContent);\n out(chalk.gray(` ✓ Appended RLS policies to migration file: ${path.basename(newestMigrationFile)}`));\n\n // Re-hash the migration directory\n out(chalk.gray(\" Re-hashing migration files...\"));\n await runAtlas(\"migrate\", [\"hash\", \"--dir\", \"file://drizzle/migrations\"], collectionsPath);\n out(chalk.gray(\" ✓ Migration directory checksum updated successfully.\"));\n }\n }\n }\n } catch (err) {\n outWarn(chalk.yellow(` ⚠️ Failed to append policies or re-hash migration: ${err instanceof Error ? err.message : String(err)}`));\n }\n\n if (!wroteNewMigration) {\n // Reachable whenever the only thing that changed is something Atlas\n // cannot see — a `search` block, a `vector` property, or a\n // `securityRules` edit. There is no new file to carry it, and the\n // previous migration must not be reopened: it has already run\n // wherever this project is deployed.\n out(chalk.gray(\n \" ℹ No migration written — nothing in this change is visible to Atlas.\\n\" +\n \" Search, vector, trigger and RLS DDL are applied by `rebase db push`, and at\\n\" +\n \" boot by the schema ensure. For a migration-only deployment, add\\n\" +\n \" drizzle/search.sql, drizzle/vector.sql, drizzle/triggers.sql and\\n\" +\n \" drizzle/policies.sql to a migration by hand.\"\n ));\n }\n\n out(\"\");\n out(` You can now run ${chalk.bold.green(\"rebase db migrate\")} to apply the migrations to your database.`);\n out(\"\");\n } else {\n out(\"\");\n out(chalk.bold(` 🗄️ Rebase DB ${subcommand.charAt(0).toUpperCase() + subcommand.slice(1)}`));\n out(\"\");\n\n if (subcommand === \"push\") {\n out(chalk.gray(\" Step 1/3: Generating Drizzle schema & Postgres DDL from collections...\"));\n out(\"\");\n await schemaCommand(\"generate\", rawArgs);\n await generatePostgresDdlCommand(rawArgs);\n out(\"\");\n const dryRun = argsList[\"--dry-run\"] === true;\n out(chalk.gray(dryRun\n ? \" Step 2/3: Planning the change against the database (nothing is applied)...\"\n : \" Step 2/3: Pushing schema to database with Atlas...\"));\n out(\"\");\n const databaseUrl = process.env.DATABASE_URL;\n // Skipped under --dry-run: this creates the auth schema and its\n // functions, which is a write. \"Show me what would happen\" that\n // changes something on the way is not a plan.\n if (databaseUrl && !dryRun) {\n await ensureAuthSchemaAndFunctions(databaseUrl);\n }\n\n // Preview the plan before touching data. `atlas schema apply` with\n // --auto-approve will silently DROP COLUMN on a field removal and\n // drop+add on a rename, so we first dry-run to obtain the planned\n // SQL and gate anything destructive.\n const plan = await runAtlas(\n \"schema\",\n [\"apply\", \"--to\", \"file://drizzle/schema.sql\", \"--dry-run\"],\n collectionsPath,\n { captureStdout: true }\n );\n const destructive = detectDestructiveStatements(plan);\n\n // A generated column makes every column it reads immutable to\n // Atlas: PostgreSQL refuses `ALTER COLUMN … TYPE` and `DROP COLUMN`\n // while one depends on it, and `schema apply` runs its plan in a\n // single transaction — so one refusal rolls back the whole push,\n // including the statements that had nothing to do with it.\n //\n // Atlas cannot avoid planning it. The search column is hidden from\n // its view on purpose (`searchExcludePatterns`), because a desired\n // state that never mentions the column reads to Atlas as an\n // instruction to drop it. So the dependant is invisible exactly\n // where it would have to be visible.\n //\n // Rebase owns those columns, so it takes them out of the way and\n // `applySearchDdl` puts them back below — the same drop-and-re-apply\n // the search stamp guard already prescribes when a block changes.\n const generatedConflicts = databaseUrl\n ? findGeneratedColumnConflicts(\n parseColumnMutations(plan),\n await queryGeneratedColumnDependencies(databaseUrl)\n )\n : [];\n const { managed: rebuildable, foreign: unowned } = partitionByOwnership(\n generatedConflicts,\n collectionsPath ? await getSearchExcludes(collectionsPath) : []\n );\n\n // `--dry-run` stops here, having printed the SQL and nothing else.\n //\n // It exists because the only way to see this plan was to trigger\n // the destructive gate, and the gate prints the plan while exiting\n // 1 — so \"what would this do?\" was answerable only by a command\n // that looked like a failure, and unanswerable at all when the\n // change was additive. An agent with no way to show the SQL either\n // asks a human to approve something neither of them has read, or\n // runs the push to find out.\n if (dryRun) {\n out(chalk.gray(\" Step 3/3: --dry-run — nothing was applied.\"));\n out(\"\");\n if (plan.trim()) {\n out(chalk.bold(\" Planned changes:\"));\n out(chalk.gray(plan.trim().split(\"\\n\").map((l) => ` ${l}`).join(\"\\n\")));\n } else {\n out(chalk.green(\" ✓ No changes: the database already matches these collections.\"));\n }\n out(\"\");\n if (rebuildable.length > 0) {\n out(chalk.gray(` ${rebuildable.length} generated column(s) would be dropped before the apply and`));\n out(chalk.gray(\" rebuilt from search.sql after it — Postgres cannot retype a column\"));\n out(chalk.gray(\" while one reads it:\"));\n for (const conflict of rebuildable) {\n out(chalk.gray(` ${describeConflict(conflict)}`));\n }\n out(\"\");\n }\n if (unowned.length > 0) {\n outWarn(formatForeignGeneratedColumnBanner(unowned));\n }\n if (destructive.length > 0) {\n outWarn(chalk.yellow(` ⚠️ ${destructive.length} of those DESTROY data:`));\n for (const d of destructive) {\n outWarn(chalk.red(` ${d.kind}: `) + chalk.gray(d.statement.replace(/\\s+/g, \" \")));\n }\n outWarn(\"\");\n outWarn(chalk.yellow(\" Applying them needs `rebase db push --allow-destructive`. Back up first: rebase db backup\"));\n outWarn(\"\");\n }\n out(chalk.gray(\" The auth schema step was skipped, because it writes. A real push runs it first.\"));\n out(\"\");\n return;\n }\n\n // Before the destructive gate, and separately from it: this is not a\n // change the operator can approve their way through. Rebase has no\n // copy of the expression, so there is nothing to put back.\n if (unowned.length > 0) {\n outError(formatForeignGeneratedColumnBanner(unowned));\n process.exit(1);\n }\n\n const allowDestructive = argsList[\"--allow-destructive\"] === true || argsList[\"--yes\"] === true;\n const decision = decidePushSafety({\n destructiveCount: destructive.length,\n allowDestructive,\n interactive: process.stdin.isTTY === true\n });\n\n if (destructive.length > 0) {\n outWarn(chalk.yellow(` ⚠️ This push includes ${destructive.length} destructive change(s) that will DESTROY data:`));\n outWarn(\"\");\n for (const d of destructive) {\n outWarn(chalk.red(` ${d.kind}: `) + chalk.gray(d.statement.replace(/\\s+/g, \" \")));\n }\n outWarn(\"\");\n outWarn(chalk.yellow(\" Full planned changes:\"));\n outWarn(chalk.gray(plan.trim().split(\"\\n\").map((l) => ` ${l}`).join(\"\\n\")));\n outWarn(\"\");\n\n if (decision === \"refuse\") {\n outError(chalk.red(\" ✗ Aborting: destructive changes require confirmation.\"));\n outError(chalk.gray(\" Re-run interactively, or pass --allow-destructive to proceed. Back up first: rebase db backup\"));\n process.exit(1);\n }\n if (decision === \"confirm\") {\n const confirmed = await promptConfirm(\n chalk.yellow(\" Type 'yes' to apply these destructive changes (this cannot be undone): \")\n );\n if (!confirmed) {\n out(chalk.gray(\" Aborted. No changes were made.\"));\n process.exit(1);\n }\n } else {\n // decision === \"apply\" via --allow-destructive\n outWarn(chalk.yellow(\" Proceeding because --allow-destructive was passed.\"));\n }\n }\n\n if (rebuildable.length > 0 && databaseUrl) {\n for (const conflict of rebuildable) {\n out(chalk.gray(` Dropping ${describeConflict(conflict)} — it reads a column this push retypes.`));\n }\n await dropGeneratedColumns(databaseUrl, dropGeneratedColumnStatements(rebuildable));\n }\n\n try {\n await runAtlas(\"schema\", [\"apply\", \"--to\", \"file://drizzle/schema.sql\", \"--auto-approve\"], collectionsPath);\n } catch (err) {\n // Atlas rolled its transaction back, so the columns those\n // expressions read are as they were and the definitions in\n // search.sql still fit. Put them back before surfacing the\n // failure: a push that fails must not also leave search broken.\n if (rebuildable.length > 0 && databaseUrl) {\n out(chalk.gray(\" The apply failed — rebuilding the generated columns it needed out of the way.\"));\n await applySearchDdl(databaseUrl);\n }\n throw err;\n }\n out(\"\");\n \n if (databaseUrl) {\n await ensureAuthTables(databaseUrl, collectionsPath);\n // After the tables exist and before the policies: the vector and\n // search columns are `ALTER TABLE ... ADD COLUMN`, and a policy\n // may reference the table they are added to.\n await applyVectorDdl(databaseUrl);\n await applySearchDdl(databaseUrl);\n await applyTriggersDdl(databaseUrl);\n await applyPolicies(databaseUrl);\n await reconcilePolicies(databaseUrl, collectionsPath);\n await ensureRlsUserRole(databaseUrl);\n await retireLegacyAuthSchema(databaseUrl);\n\n // The push worked, so the throwaway schema copy Atlas planned\n // against has nothing left to say. It was kept forever, one per\n // target, and the only notice was `rebase db branch prune`\n // reporting them. On a failed push we never reach this line —\n // deliberately: there the scratch database is the evidence.\n // And only the one this run created: a scratch database the\n // user made by hand is theirs to keep.\n if (scratchDatabaseCreatedHere) {\n await dropDevDatabase(databaseUrl, getDevDatabaseUrl(databaseUrl));\n }\n } else {\n outWarn(chalk.yellow(\" ⚠️ DATABASE_URL not found in environment, skipping RLS policies application.\"));\n }\n } else if (subcommand === \"migrate\") {\n const databaseUrl = process.env.DATABASE_URL;\n if (databaseUrl) {\n await ensureAuthSchemaAndFunctions(databaseUrl);\n }\n const extraArgs = argsList._.filter(arg => arg !== \"migrate\");\n // `--baseline <version>` is relayed to Atlas as its own: it records\n // the version as already applied and starts from the next one. The\n // database a Rebase boot has provisioned is exactly the case it is\n // for, and without it `migrate apply` there is unusable — see\n // `formatBaselineRemedy`, which is what prints when it is missing.\n const baseline = argsList[\"--baseline\"];\n if (baseline) {\n out(chalk.gray(` Recording ${baseline} as already applied, then migrating from the next one.`));\n out(\"\");\n }\n await runAtlas(\n \"migrate\",\n [\n \"apply\",\n \"--dir\", \"file://drizzle/migrations\",\n ...(baseline ? [\"--baseline\", baseline] : []),\n ...extraArgs\n ],\n collectionsPath\n );\n if (databaseUrl) {\n await ensureRlsUserRole(databaseUrl);\n await retireLegacyAuthSchema(databaseUrl);\n }\n }\n\n out(\"\");\n out(chalk.green(` ✓ rebase db ${subcommand} completed successfully.`));\n out(\"\");\n }\n}\n\nasync function ensureAuthSchemaAndFunctions(databaseUrl: string): Promise<void> {\n try {\n const { Client } = await import(\"pg\");\n const client = new Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n // Creates the `rebase` schema as its first statement, which also\n // covers the schema Atlas puts its revision table in\n // (`--revisions-schema rebase`). That used to need a separate,\n // deliberately migration-stream-excluded statement here, because the\n // helper functions lived in `auth` and creating `rebase` from the\n // preamble would have made Atlas plan a DROP for it. The generator\n // now always declares `rebase` in the desired schema, so there is\n // nothing to keep out.\n await client.query(RLS_BOOTSTRAP_SQL);\n } finally {\n await client.end();\n }\n } catch (err) {\n outWarn(chalk.yellow(` ⚠️ Failed to bootstrap the RLS helper functions: ${err instanceof Error ? err.message : String(err)}`));\n }\n}\n\n/**\n * Create the framework auth tables (e.g. `rebase.users`) that the generated RLS\n * policies reference, before `applyPolicies` runs. Mirrors what the server does\n * at boot (`PostgresBootstrapper.initializeAuth` → `ensureAuthTablesExist`).\n *\n * Without this, `rebase db push` against a database that has never booted the\n * server fails while applying policies with `relation \"rebase.users\" does not\n * exist` — the documented first-run does `db push` *before* the first `dev`.\n * `ensureAuthTablesExist` is idempotent (CREATE TABLE IF NOT EXISTS), so it is\n * safe to run on every push and harmless once the server has also created them.\n */\nasync function ensureAuthTables(databaseUrl: string, collectionsPath: string): Promise<void> {\n try {\n const { drizzle } = await import(\"drizzle-orm/node-postgres\");\n const { ensureAuthTablesExist } = await import(\"./auth/ensure-tables\");\n const { loadCollections } = await import(\"./schema/doctor\");\n const { Client } = await import(\"pg\");\n\n const collections = await loadCollections(path.resolve(process.cwd(), collectionsPath));\n // The auth collection is flagged with `auth: true` or `auth: { enabled: true }`.\n const authCollection = collections.find((c) => {\n const a = c.auth;\n return a === true || (typeof a === \"object\" && a !== null && a.enabled === true);\n });\n\n const client = new Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n await ensureAuthTablesExist(drizzle(client), authCollection);\n } finally {\n await client.end();\n }\n } catch (err) {\n outWarn(chalk.yellow(` ⚠️ Failed to ensure framework auth tables: ${err instanceof Error ? err.message : String(err)}`));\n }\n}\n\n/**\n * Provision the restricted `rebase_user` role right after schema changes land,\n * so grants cover freshly created tables (default privileges cover future\n * ones). Only needed — and only possible without extra setup — when the\n * connection would bypass RLS (superuser / BYPASSRLS / table owner).\n */\nasync function ensureRlsUserRole(databaseUrl: string): Promise<void> {\n // Every failure in here used to escape uncaught, and `db migrate`'s caller\n // turns that into a bare `process.exit(1)` — so the migration would apply,\n // print `-- ok`, and then the command would die with NO output whatsoever\n // and a non-zero status. Seen with a module-resolution error inside the\n // dynamic import, where the entire diagnosis was one silent exit code.\n //\n // Reported rather than rethrown, and deliberately not fatal: the schema\n // change has already landed at this point, so failing the command implies a\n // rollback that did not happen. What is actually lost is the role\n // provisioning, and the message says so and how to finish it by hand.\n // No `auth`: the RLS helpers live in `rebase` now, and a schema the\n // framework no longer creates must not be granted on — on a Supabase\n // database that would hand the end-user role USAGE on their auth schema.\n const schemas = [\"public\", \"rebase\"];\n let rls: typeof import(\"./security/rls-enforcement\");\n try {\n rls = await import(\"./security/rls-enforcement\");\n } catch (err) {\n // A module-resolution failure here is a build problem, not a database\n // one, and it is exactly the case that used to produce the silent exit.\n outError(chalk.red(\n `\\n ✗ Could not load the RLS provisioning module: ${err instanceof Error ? err.message : String(err)}`\n ));\n return;\n }\n\n try {\n const { Client } = await import(\"pg\");\n const client = new Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n const runSql = async (text: string) => (await client.query(text)).rows as Record<string, unknown>[];\n const posture = await rls.detectConnectionPosture(runSql);\n if (posture.privileged) {\n await rls.ensureAppRole(runSql, schemas);\n out(chalk.gray(` ✓ RLS role \"${rls.REBASE_USER_ROLE}\" provisioned/refreshed.`));\n }\n } finally {\n await client.end();\n }\n } catch (err) {\n outError(chalk.red(\n `\\n ✗ The schema change was applied, but the \"${rls.REBASE_USER_ROLE}\" role could not be ` +\n `provisioned: ${err instanceof Error ? err.message : String(err)}`\n ));\n outError(chalk.gray(rls.appRoleSetupInstructions(\"your database user\", schemas)));\n }\n}\n\n/**\n * Retire the pre-1.0 `auth` schema, once nothing depends on it any more.\n *\n * Runs last on purpose. Postgres refuses to drop a function an RLS policy still\n * calls, so this only succeeds after the policies above have been rewritten to\n * `rebase.uid()`. See `dropLegacyAuthSchema` for what it reports when something\n * hand-written is still holding the schema open, and DROP_LEGACY_AUTH_SCHEMA_SQL\n * for the guards that keep it off a Supabase `auth` schema.\n */\nasync function retireLegacyAuthSchema(databaseUrl: string): Promise<void> {\n try {\n const { Client } = await import(\"pg\");\n const client = new Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n await dropLegacyAuthSchema(\n async (text) => (await client.query(text)).rows as Record<string, unknown>[],\n {\n info: (m) => out(chalk.gray(` ${m}`)),\n warn: (m) => outWarn(chalk.yellow(` ⚠️ ${m}`))\n }\n );\n } finally {\n await client.end();\n }\n } catch {\n // Connection-level failure only; the schema is inert either way.\n }\n}\n\nasync function applyPolicies(databaseUrl: string): Promise<void> {\n try {\n const policiesPath = path.resolve(process.cwd(), \"drizzle\", \"policies.sql\");\n if (!fs.existsSync(policiesPath)) return;\n \n out(chalk.gray(\" Step 3/3: Applying RLS policies to database...\"));\n out(\"\");\n \n const policiesContent = fs.readFileSync(policiesPath, \"utf-8\");\n const { Client } = await import(\"pg\");\n const client = new Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n await client.query(policiesContent);\n out(chalk.green(\" ✓ RLS policies applied successfully.\"));\n } finally {\n await client.end();\n }\n } catch (err) {\n const hint = diagnoseDbError(err, databaseUrl);\n if (hint) {\n outError(hint);\n } else {\n outError(chalk.red(` ✗ Failed to apply RLS policies: ${err instanceof Error ? err.message : String(err)}`));\n }\n process.exit(1);\n }\n}\n\n/**\n * Remove the policies an earlier push superseded but never dropped.\n *\n * `policies.sql` only DROPs the names it is about to CREATE, and a rule's\n * generated name contains a hash of its own semantics — so editing a rule\n * writes a *new* policy and abandons the old one. Postgres ORs PERMISSIVE\n * policies together, which makes an abandoned grant outrank every tightening\n * that replaced it, and push reported success the whole time.\n *\n * Runs after `applyPolicies` so the current policies are already in place: the\n * drift check then sees exactly the set that should survive, and anything else\n * on a managed table is by definition left over.\n */\nasync function reconcilePolicies(databaseUrl: string, collectionsPath: string): Promise<void> {\n try {\n const { checkPolicyDrift, dropOrphanedPolicies, formatPolicyDrift, hasDrift } =\n await import(\"./security/policy-drift\");\n const { loadCollections } = await import(\"./schema/doctor\");\n\n const collections = await loadCollections(path.resolve(process.cwd(), collectionsPath));\n const { Client } = await import(\"pg\");\n const client = new Client({ connectionString: databaseUrl });\n await client.connect();\n try {\n const drift = await checkPolicyDrift(client as never, collections);\n const { dropped, kept } = await dropOrphanedPolicies(client as never, drift, collections);\n\n for (const p of dropped) {\n out(chalk.gray(` ✓ Dropped superseded policy \"${p.name}\" on ${p.schema}.${p.table}`));\n }\n if (dropped.length > 0) {\n out(chalk.green(` ✓ Removed ${dropped.length} superseded RLS ${dropped.length === 1 ? \"policy\" : \"policies\"}.`));\n }\n\n // Custom-named orphans are indistinguishable from policies someone\n // wrote in SQL deliberately, so they are reported, never dropped.\n if (kept.length > 0) {\n outWarn(chalk.yellow(\" ⚠️ Policies in the database that no collection describes:\"));\n for (const p of kept) {\n outWarn(chalk.yellow(` • ${p.schema}.${p.table} → \"${p.name}\" (${p.command} TO ${p.roles.join(\", \")})`));\n }\n outWarn(chalk.yellow(\" These still grant access. Drop them by hand if they are stale.\"));\n }\n\n // Missing/diverged are not push's to fix, but staying silent about\n // them is how a database ends up not matching its config.\n const remaining = { ...drift, orphaned: kept };\n if (hasDrift(remaining) && (remaining.missing.length > 0 || remaining.diverged.length > 0)) {\n outWarn(chalk.yellow(\" ⚠️ RLS policies do not match your collections:\"));\n outWarn(formatPolicyDrift({ ...remaining, orphaned: [] }));\n }\n } finally {\n await client.end();\n }\n } catch (err) {\n outWarn(chalk.yellow(` ⚠️ Could not reconcile RLS policies: ${err instanceof Error ? err.message : String(err)}`));\n }\n}\n\n/**\n * Flags the `branch` subcommands take.\n *\n * Declared as an `arg` spec rather than picked out of argv by hand, which is\n * both how the rest of this file parses flags and how the documentation\n * verifier discovers them: it reads `arg({ … })` specs out of this source, so a\n * flag parsed any other way is one it reports as unrunnable in every page that\n * documents it. Hand-rolled parsing here cost exactly that — `--older-than`\n * worked and the docs check called it a command a reader cannot run.\n */\nconst BRANCH_FLAGS = {\n \"--older-than\": String,\n \"--include-dev-diff\": Boolean,\n \"--from\": String,\n \"--yes\": Boolean,\n \"-y\": \"--yes\"\n} as const;\n\nasync function branchCommand(rawArgs: string[]): Promise<void> {\n const branchAction = rawArgs[2]; // create, list, delete, info\n\n if (!branchAction || branchAction === \"--help\") {\n printBranchHelp();\n return;\n }\n\n // Before anything connects: a name that is not the name asked for is worth\n // refusing, and it costs a database round-trip to discover later.\n const extras = unexpectedBranchArgs(rawArgs.slice(2));\n if (extras.length > 0) {\n outError(\"\");\n outError(chalk.red(` ✗ Unexpected argument${extras.length > 1 ? \"s\" : \"\"}: ${extras.join(\" \")}`));\n outError(\"\");\n outError(chalk.gray(` ${chalk.bold(\"rebase db branch\")} takes one name. A branch name may contain letters,`));\n outError(chalk.gray(\" digits, underscores and hyphens — no spaces.\"));\n if (rawArgs[3]) {\n outError(chalk.gray(` Did you mean: ${chalk.cyan(`rebase db branch ${branchAction} ${[rawArgs[3], ...extras].join(\"-\")}`)}`));\n }\n outError(\"\");\n process.exit(1);\n }\n\n // Load .env for DATABASE_URL\n try {\n const dotenv = await import(\"dotenv\");\n const envPath = process.env.DOTENV_CONFIG_PATH;\n if (envPath) {\n dotenv.config({ path: envPath, quiet: true });\n } else {\n dotenv.config({ quiet: true });\n }\n } catch {\n // dotenv may not be installed\n }\n\n const databaseUrl = process.env.DATABASE_URL || process.env.ADMIN_CONNECTION_STRING;\n if (!databaseUrl) {\n outError(chalk.red(\"✗ DATABASE_URL is not set. Make sure your .env file is configured.\"));\n process.exit(1);\n }\n\n // Dynamic imports to avoid loading heavy deps when not needed\n const { DatabasePoolManager } = await import(\"./databasePoolManager\");\n const { BranchService } = await import(\"./services/BranchService\");\n const { drizzle } = await import(\"drizzle-orm/node-postgres\");\n const { Pool } = await import(\"pg\");\n\n const pool = new Pool({ connectionString: databaseUrl,\nmax: 3 });\n const db = drizzle(pool);\n const poolManager = new DatabasePoolManager(databaseUrl);\n const branchService = new BranchService(db, poolManager);\n\n // Ensure metadata table exists\n await branchService.ensureBranchMetadataTable();\n\n try {\n switch (branchAction) {\n case \"create\": {\n const name = rawArgs[3];\n if (!name) {\n outError(chalk.red(\"✗ Branch name is required.\"));\n out(chalk.gray(\" Usage: rebase db branch create <name> [--from <source>]\"));\n process.exit(1);\n }\n let source: string | undefined;\n const fromIdx = rawArgs.indexOf(\"--from\");\n if (fromIdx !== -1 && rawArgs[fromIdx + 1]) {\n source = rawArgs[fromIdx + 1];\n }\n const force = rawArgs.includes(\"--force\");\n out(\"\");\n out(chalk.bold(\" 🌿 Creating database branch...\"));\n out(chalk.gray(` Name: ${name}`));\n if (source) out(chalk.gray(` Source: ${source}`));\n if (force) out(chalk.gray(\" Force: other connections to the source will be disconnected\"));\n out(\"\");\n const branch = await branchService.createBranch(name, { source, force });\n out(chalk.green(` ✓ Branch \"${branch.name}\" created successfully.`));\n out(chalk.gray(` Database: rb_${branch.name}`));\n out(chalk.gray(` Parent: ${branch.parentDatabase}`));\n out(\"\");\n break;\n }\n\n case \"list\": {\n const branches = await branchService.listBranches();\n out(\"\");\n if (branches.length === 0) {\n out(chalk.gray(\" No branches found. Create one with: rebase db branch create <name>\"));\n } else {\n out(chalk.bold(` 🌿 ${branches.length} branch(es):`));\n out(\"\");\n for (const b of branches) {\n const size = b.sizeBytes != null\n ? chalk.gray(` (${formatBytes(b.sizeBytes)})`)\n : \"\";\n const age = chalk.gray(` — created ${timeAgo(b.createdAt)}`);\n out(` ${chalk.green(\"●\")} ${chalk.bold(b.name)}${size}${age}`);\n out(chalk.gray(` from ${b.parentDatabase}`));\n }\n }\n out(\"\");\n break;\n }\n\n case \"delete\": {\n const name = rawArgs[3];\n if (!name) {\n outError(chalk.red(\"✗ Branch name is required.\"));\n out(chalk.gray(\" Usage: rebase db branch delete <name>\"));\n process.exit(1);\n }\n out(\"\");\n out(chalk.bold(` 🗑️ Deleting branch \"${name}\"...`));\n await branchService.deleteBranch(name, { force: rawArgs.includes(\"--force\") });\n out(chalk.green(` ✓ Branch \"${name}\" deleted.`));\n out(\"\");\n break;\n }\n\n case \"info\": {\n const name = rawArgs[3];\n if (!name) {\n outError(chalk.red(\"✗ Branch name is required.\"));\n out(chalk.gray(\" Usage: rebase db branch info <name>\"));\n process.exit(1);\n }\n const info = await branchService.getBranchInfo(name);\n out(\"\");\n if (!info) {\n // Exit 1, like `delete` on a branch that is not there.\n // These two answered the same question — \"is there a branch\n // called this?\" — and disagreed about how to say no: delete\n // failed, info printed `✗ Branch \"x\" not found.` and exited\n // 0. Anything reading the status saw success, so\n // `rebase db branch info \"$b\" && deploy_against \"$b\"` ran\n // the deploy against a branch that does not exist.\n outError(chalk.red(` ✗ Branch \"${name}\" not found.`));\n out(\"\");\n process.exit(1);\n } else {\n out(chalk.bold(` 🌿 Branch: ${info.name}`));\n out(chalk.gray(` Database: rb_${info.name}`));\n out(chalk.gray(` Parent: ${info.parentDatabase}`));\n out(chalk.gray(` Created: ${info.createdAt.toISOString()}`));\n if (info.sizeBytes != null) {\n out(chalk.gray(` Size: ${formatBytes(info.sizeBytes)}`));\n }\n }\n out(\"\");\n break;\n }\n\n case \"prune\": {\n const parsed = arg(BRANCH_FLAGS, { argv: rawArgs.slice(3), permissive: true });\n const olderThanRaw = parsed[\"--older-than\"] ?? null;\n const olderThanDays = olderThanRaw == null ? null : parseOlderThan(olderThanRaw);\n if (olderThanRaw != null && olderThanDays == null) {\n outError(chalk.red(` ✗ --older-than \"${olderThanRaw}\" is not a duration.`));\n out(chalk.gray(\" Use a number of days (14), or 14d / 2w.\"));\n process.exit(1);\n }\n\n const includeDevDiff = parsed[\"--include-dev-diff\"] === true;\n const { rows, databases } = await branchService.pruneCandidates();\n const plan = planPrune({ rows, databases, branchPrefix: \"rb_\" }, { olderThanDays });\n\n out(\"\");\n if (planIsEmpty(plan, includeDevDiff)) {\n out(chalk.gray(\" Nothing to prune.\"));\n if (!olderThanDays && rows.length > 0) {\n out(chalk.gray(` ${rows.length} branch(es) are healthy — --older-than 14 also removes old ones.`));\n }\n if (!includeDevDiff && plan.devDiff.length > 0) {\n out(chalk.gray(` ${plan.devDiff.length} Atlas scratch database(s) left over from db push;`));\n out(chalk.gray(\" --include-dev-diff removes those too.\"));\n }\n out(\"\");\n break;\n }\n\n out(chalk.bold(\" 🧹 Prune plan\"));\n out(\"\");\n for (const row of plan.staleRows) {\n out(` ${chalk.yellow(\"○\")} ${chalk.bold(row.name)} ${chalk.gray(\"— registered, but its database is gone; the entry will be removed\")}`);\n }\n for (const dbName of plan.orphanDatabases) {\n out(` ${chalk.yellow(\"○\")} ${chalk.bold(dbName)} ${chalk.gray(\"— a branch database with no entry; the database will be dropped\")}`);\n }\n for (const { branch, ageDays } of plan.expired) {\n out(` ${chalk.red(\"●\")} ${chalk.bold(branch.name)} ${chalk.gray(`— ${ageDays} days old; branch and database will be dropped`)}`);\n }\n if (includeDevDiff) {\n for (const dbName of plan.devDiff) {\n out(` ${chalk.red(\"●\")} ${chalk.bold(dbName)} ${chalk.gray(\"— Atlas scratch database; will be dropped\")}`);\n }\n } else if (plan.devDiff.length > 0) {\n out(chalk.gray(` (${plan.devDiff.length} Atlas scratch database(s) not listed — --include-dev-diff)`));\n }\n out(\"\");\n\n if (parsed[\"--yes\"] !== true) {\n // Dropping a database is not undoable and a branch may be\n // the only copy of an afternoon's work.\n const confirmed = await promptConfirm(\" Remove these? (y/N) \");\n if (!confirmed) {\n out(chalk.gray(\" Nothing was changed.\"));\n out(\"\");\n break;\n }\n }\n\n let removed = 0;\n for (const row of plan.staleRows) {\n await branchService.forgetBranchRow(row.name);\n removed += 1;\n }\n for (const dbName of plan.orphanDatabases) {\n await branchService.dropDatabase(dbName);\n removed += 1;\n }\n for (const { branch } of plan.expired) {\n await branchService.deleteBranch(branch.name);\n removed += 1;\n }\n if (includeDevDiff) {\n for (const dbName of plan.devDiff) {\n await branchService.dropDatabase(dbName);\n removed += 1;\n }\n }\n\n out(chalk.green(` ✓ Pruned ${removed} item(s).`));\n out(\"\");\n break;\n }\n\n default:\n outError(chalk.red(`Unknown branch action: \"${branchAction}\".`));\n printBranchHelp();\n process.exit(1);\n }\n } finally {\n await poolManager.shutdown();\n await pool.end();\n }\n}\n\nfunction printBranchHelp() {\n out(`\n${chalk.bold(\"rebase db branch\")} — Database branching commands\n\n${chalk.green.bold(\"Usage\")}\n rebase db branch ${chalk.blue(\"<command>\")} [options]\n\n${chalk.green.bold(\"Commands\")}\n ${chalk.blue.bold(\"create\")} <name> [--from <source>] Create a new branch\n ${chalk.blue.bold(\"list\")} List all branches\n ${chalk.blue.bold(\"switch\")} [<name>|--off] Point this checkout at a branch\n ${chalk.blue.bold(\"delete\")} <name> Delete a branch\n ${chalk.blue.bold(\"info\")} <name> Show branch details\n ${chalk.blue.bold(\"prune\")} [--older-than <14|14d|2w>] Remove branches nothing is using\n\n${chalk.green.bold(\"Why prune\")}\n Every branch is a full-size copy — CREATE DATABASE ... TEMPLATE duplicates the\n files on disk, so five branches of a 100GB database cost 500GB. Prune also\n finds the two ways branches drift: an entry whose database was dropped\n outside Rebase, and a branch database whose entry never got written.\n\n${chalk.green.bold(\"Options\")}\n ${chalk.blue.bold(\"--force\")} Disconnect other sessions first.\n Postgres refuses to copy or drop a database\n anything else is connected to — usually your\n own \\`rebase dev\\`.\n ${chalk.blue.bold(\"--include-dev-diff\")} Also prune the Atlas scratch databases\n \\`db push\\` leaves behind.\n ${chalk.blue.bold(\"--yes, -y\")} Skip prune's confirmation prompt. Dropping a\n branch is not undoable, so this is the flag\n a CI job passes and a person usually should not.\n\n${chalk.green.bold(\"Examples\")}\n ${chalk.gray(\"# Create a branch and work on it\")}\n rebase db branch create feature_auth\n rebase db branch switch feature_auth\n\n ${chalk.gray(\"# Create a branch from a specific source\")}\n rebase db branch create staging --from production\n\n ${chalk.gray(\"# Remove branches older than two weeks, and anything orphaned\")}\n rebase db branch prune --older-than 2w\n\n ${chalk.gray(\"# List all branches\")}\n rebase db branch list\n\n ${chalk.gray(\"# Delete a branch\")}\n rebase db branch delete feature_auth\n`);\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;\n}\n\n/** A branch's age, for \"…created 6d ago\". */\nfunction timeAgo(date: Date): string {\n // No horizon: a branch created a year ago should still report an age here,\n // rather than fall back to a bare date in a one-line list entry.\n return formatRelativeTime(date, { maxMs: Number.POSITIVE_INFINITY }) ?? \"unknown\";\n}\n\n\n\n/** Set when this process created the Atlas scratch database; see `ensureDevDatabaseExists`. */\nlet scratchDatabaseCreatedHere = false;\n\nasync function runAtlas(\n domain: \"schema\" | \"migrate\",\n args: string[],\n collectionsPath?: string,\n opts: { captureStdout?: boolean } = {}\n): Promise<string> {\n const atlasBin = resolveLocalBin(\"atlas\");\n if (!atlasBin) {\n // Two very different causes, and the advice for one is a loop for the\n // other — see `diagnoseMissingBin`. This used to say \"Install it with:\n // pnpm add -D @ariga/atlas\" unconditionally, which is the exact command\n // that produces the far more common of the two states.\n outError(chalk.red(\"\\n✗ The atlas binary is missing, so the schema cannot be applied.\\n\"));\n\n // Every remedy below is package-manager specific, and this used to print\n // pnpm's unconditionally. npm 12 blocks a dependency's install scripts\n // the same way pnpm 10 does, so an npm reader was handed `pnpm\n // approve-builds` and a `\"pnpm\"` package.json key — correct advice, for\n // somebody else. Read the lockfile and answer the reader in front of us.\n const manager = detectProjectPackageManager();\n\n const diagnosis = diagnoseMissingBin(\"@ariga/atlas\");\n\n if (diagnosis === \"bin-link-missing\") {\n // The binary IS on disk; only the `node_modules/.bin` shim that\n // points at it is not. pnpm produces this when it writes the link\n // before the script that creates the target (\"Failed to create bin\n // … ENOENT\"), and so does a tree copied without its symlinks.\n // Sending this reader to `approve-builds` does nothing: nothing is\n // blocked.\n outError(chalk.yellow(\" @ariga/atlas and its binary are both on disk — only the\\n\"\n + \" node_modules/.bin/atlas link that puts it on PATH is missing.\\n\"));\n outError(chalk.gray(\n \" Usually a half-written install: the link is created before the script that\\n\"\n + \" downloads the target, so an interrupted or copied tree keeps the binary and\\n\"\n + \" loses the shim.\\n\"\n ));\n outError(\" Fix it with:\\n\");\n outError(chalk.bold(` ${describeReinstallCommand(manager)}\\n`));\n } else if (diagnosis === \"build-script-blocked\") {\n outError(chalk.yellow(\" @ariga/atlas IS installed — only its binary is missing.\\n\"));\n outError(chalk.gray(\n \" It downloads that binary in a `preinstall` script, and pnpm 10+ and npm 12+\\n\" +\n \" do not run a dependency's scripts unless you allow it. The install still\\n\" +\n \" exits 0, so the only sign is a line several screens up: pnpm's\\n\" +\n \" `Ignored build scripts: @ariga/atlas`, or npm's `install scripts blocked`.\\n\"\n ));\n outError(\" Fix it with either:\\n\");\n for (const line of describeBuildScriptRemedy(\"@ariga/atlas\", manager)) {\n outError(line ? chalk.bold(line) : \"\");\n }\n outError(\"\");\n } else {\n outError(chalk.gray(\" It is not installed in this project.\\n\"));\n outError(\" Install it with:\\n\");\n outError(chalk.bold(` ${describeDevAddCommand(\"@ariga/atlas\", manager)}\\n`));\n outError(chalk.gray(\n \" If the install then reports blocked or ignored build scripts, allow them too —\\n\" +\n \" the package carries a `preinstall` script that fetches the binary.\\n\"\n ));\n }\n process.exit(1);\n }\n\n const env = { ...process.env as Record<string, string> };\n try {\n const dotenv = await import(\"dotenv\");\n const envPaths = [\n process.env.DOTENV_CONFIG_PATH,\n path.resolve(process.cwd(), \".env\"),\n path.resolve(process.cwd(), \"../.env\"),\n path.resolve(process.cwd(), \"../../.env\")\n ].filter(Boolean) as string[];\n\n for (const p of envPaths) {\n if (fs.existsSync(p)) {\n const parsed = dotenv.config({ path: p, quiet: true });\n if (parsed.parsed) {\n for (const [key, val] of Object.entries(parsed.parsed)) {\n if (env[key] === undefined) {\n env[key] = val;\n }\n }\n break;\n }\n }\n }\n } catch {\n // ignore\n }\n\n const databaseUrl = env.DATABASE_URL;\n if (!databaseUrl) {\n outError(chalk.red(\"✗ DATABASE_URL is not set. Make sure your .env file is configured.\"));\n process.exit(1);\n }\n\n // Pre-flight: verify the database is reachable before running Atlas.\n // This catches ECONNREFUSED / auth failures with a friendly banner\n // instead of letting Atlas surface a raw error.\n await checkDatabaseConnectivity(databaseUrl);\n\n const devDatabaseUrl = getDevDatabaseUrl(databaseUrl);\n // Remember whether the scratch database is ours: one a user created by\n // hand — the remedy for a role without CREATEDB — must survive the push,\n // or that user is back at the same refusal next time.\n if (await ensureDevDatabaseExists(databaseUrl, devDatabaseUrl)) scratchDatabaseCreatedHere = true;\n\n // Atlas speaks libpq, which rejects the `sslmode=no-verify` that\n // node-postgres accepts — see `forLibpq`. Rewritten only for the argv, so\n // everything above still connects with the URL as configured.\n const atlasUrl = forLibpq(databaseUrl);\n const atlasDevUrl = forLibpq(devDatabaseUrl);\n\n // Everything Atlas must keep its hands off, in one list.\n //\n // Gathered only for the invocations that accept the flag — which is\n // `schema apply` and nothing else. `atlas migrate diff` and `migrate apply`\n // both reject `--exclude` outright with `unknown flag`, and passing it there\n // took `rebase db generate` and `rebase db migrate` down for every project\n // declaring a `search` block; the diff keeps the same objects out of the\n // migration afterwards instead, with `stripCarvedOutStatements`. See\n // `acceptsExcludeFlag`.\n const excludes: string[] = [];\n if (collectionsPath && acceptsExcludeFlag(domain, args)) {\n // Search and vector objects are Rebase's, not Atlas's: the desired state\n // does not carry them, so an apply left to itself would drop them.\n excludes.push(...await getSearchExcludes(collectionsPath));\n excludes.push(...await getVectorExcludes(collectionsPath));\n excludes.push(...await getTriggerExcludes(collectionsPath));\n\n // Fail CLOSED: the exclude list is the only thing shielding\n // non-collection tables from the auto-approved apply. If we can't\n // introspect the database to build it, abort rather than proceed with\n // a partial list that would let Atlas drop unmanaged tables.\n try {\n excludes.push(...await getTableExcludes(databaseUrl, collectionsPath));\n } catch (err) {\n if (err instanceof ExcludeIntrospectionError) {\n outError(chalk.red(\"\\n✗ Aborting push: could not determine which tables to protect.\"));\n outError(chalk.gray(` ${err.message}`));\n outError(chalk.gray(\" Refusing to apply — a partial exclude list could drop tables Rebase does not manage.\"));\n const hint = diagnoseDbError(err.cause ?? err, databaseUrl);\n if (hint) outError(hint);\n process.exit(1);\n }\n throw err;\n }\n\n // And the indexes on those tables that Rebase did not create. Same\n // fail-closed contract as the table list above, for the same reason: a\n // partial answer here silently drops somebody's index.\n try {\n excludes.push(...await getForeignIndexExcludes(databaseUrl, collectionsPath));\n } catch (err) {\n if (err instanceof ExcludeIntrospectionError) {\n outError(chalk.red(\"\\n✗ Aborting push: could not determine which indexes to protect.\"));\n outError(chalk.gray(` ${err.message}`));\n outError(chalk.gray(\" Refusing to apply — a partial exclude list could drop an index Rebase does not manage.\"));\n const hint = diagnoseDbError(err.cause ?? err, databaseUrl);\n if (hint) outError(hint);\n process.exit(1);\n }\n throw err;\n }\n }\n\n const atlasArgs = buildAtlasArgs({ domain, args, url: atlasUrl, devUrl: atlasDevUrl, excludes });\n\n // Stream stdout live but tee stderr so we can inspect Atlas's error text\n // for known, actionable failure modes (e.g. a dependency-drop that leaves\n // the schema half-applied) after the process exits. When capturing (used\n // for the destructive-change dry-run), pipe stdout and collect it instead.\n const subprocess = execa(atlasBin, atlasArgs, {\n cwd: process.cwd(),\n stdout: opts.captureStdout ? \"pipe\" : \"inherit\",\n stderr: \"pipe\",\n env\n });\n let stdoutText = \"\";\n if (opts.captureStdout) {\n subprocess.stdout?.on(\"data\", (chunk: Buffer) => {\n stdoutText += chunk.toString();\n });\n }\n let stderrText = \"\";\n subprocess.stderr?.on(\"data\", (chunk: Buffer) => {\n const text = chunk.toString();\n stderrText += text;\n process.stderr.write(text);\n });\n try {\n await subprocess;\n } catch {\n outError(chalk.red(`\\n✗ atlas ${domain} ${args.join(\" \")} failed.\\n`));\n // Surface actionable recovery guidance for recognized failures. The\n // Atlas-shaped ones first: they read the invocation as well as the\n // text, so they can tell `migrate apply` hitting an already-provisioned\n // database (which wants a baseline) from `schema apply` hitting a real\n // conflict. `diagnoseDbError` is the connection-level fallback, shared\n // with the boot path.\n const atlasHint = await diagnoseAtlasFailure({\n domain,\n args,\n stderr: stderrText,\n databaseUrl,\n latestMigrationVersion: latestMigrationVersion()\n });\n const hint = atlasHint ?? diagnoseDbError({ message: stderrText }, databaseUrl);\n if (hint) {\n outError(hint);\n }\n process.exit(1);\n }\n // Atlas prints the plan to stdout, but fall back to stderr so the\n // destructive-change detector never misses a plan on a version/build that\n // routes it differently.\n if (opts.captureStdout) {\n return stdoutText.trim().length > 0 ? stdoutText : stderrText;\n }\n return \"\";\n}\n\nasync function generatePostgresDdlCommand(rawArgs: string[]): Promise<void> {\n const argsList = arg(\n {\n \"--collections\": String,\n \"--output\": String,\n \"-c\": \"--collections\",\n \"-o\": \"--output\"\n },\n {\n argv: rawArgs.slice(2),\n permissive: true\n }\n );\n\n const ddl = resolveChildScript(\"generate-postgres-ddl\");\n if (!ddl.ok) {\n outError(chalk.red(childScriptError(\"DDL generator\", ddl.reason)));\n process.exit(1);\n }\n\n const collectionsPath = argsList[\"--collections\"] || path.join(\"..\", \"config\", \"collections\");\n const outputPath = argsList[\"--output\"] || path.join(\"drizzle\", \"schema.sql\");\n\n const cmdParts = [\n ddl.bin,\n ddl.script,\n `--collections=${collectionsPath}`,\n `--output=${outputPath}`\n ];\n\n try {\n await execa(cmdParts[0], cmdParts.slice(1), {\n cwd: process.cwd(),\n stdio: \"inherit\",\n env: { ...process.env as Record<string, string> }\n });\n } catch (err: unknown) {\n // The generator runs with inherited stdio, so on a non-zero exit its\n // own message is already the last useful thing on the terminal and\n // execa's wrapper (\"Command failed with exit code 1: …/tsx …\") would\n // bury it. Repeat it only when the child never got as far as speaking.\n if (typeof (err as { exitCode?: number }).exitCode === \"number\") {\n outError(chalk.red(\"✗ Postgres DDL generation failed — nothing was applied.\"));\n } else {\n outError(chalk.red(`✗ Failed to run Postgres DDL generator: ${err instanceof Error ? err.message : String(err)}`));\n }\n process.exit(1);\n }\n}\n\n/**\n * `schema stale [--fix]` — is the generated Drizzle schema older than the rule\n * that derives its foreign-key names?\n *\n * This exists for one upgrade path and is worth the command. 0.13 derives\n * `category_id` where 0.12 derived `categorie_id`; boot-ensure renames the\n * database column to match, and the project's checked-in\n * `backend/src/schema.generated.ts` is then wrong in a way nothing the developer\n * did would explain. Relation validation refuses to boot on it, permanently,\n * because the rename has already been applied and will not run again.\n *\n * `rebase dev` calls this with `--fix` before starting the backend, so the\n * upgrade behaves the way the release note says it does: the column moves and the\n * project keeps working. Without `--fix` it reports and exits non-zero, which is\n * what a build or a CI step wants.\n */\nasync function schemaStaleCommand(rawArgs: string[]): Promise<void> {\n const argsList = arg(\n {\n \"--collections\": String,\n \"--output\": String,\n \"--fix\": Boolean,\n \"-c\": \"--collections\",\n \"-o\": \"--output\",\n // Both spellings, on every command that writes a file. See\n // `OUTPUT_FLAG_ALIASES` in cli-flags.ts.\n \"--out\": \"--output\"\n },\n { argv: rawArgs.slice(2), permissive: true }\n );\n\n const collectionsPath = argsList[\"--collections\"] || path.join(\"..\", \"config\", \"collections\");\n const outputPath = argsList[\"--output\"] || path.join(\"src\", \"schema.generated.ts\");\n const schemaFile = path.resolve(process.cwd(), outputPath);\n\n const fix = Boolean(argsList[\"--fix\"]);\n const generatedExists = fs.existsSync(schemaFile);\n\n const { loadCollections } = await import(\"./schema/doctor\");\n const { findLegacyForeignKeyNames, compareGeneratedDeclarations, staleVerdict } =\n await import(\"./schema/generated-schema-staleness\");\n const { generateSchema } = await import(\"./schema/generate-drizzle-schema-logic\");\n const { relationalCollections } = await import(\"@rebasepro/common\");\n\n let stale: ReturnType<typeof findLegacyForeignKeyNames> = [];\n let differences: ReturnType<typeof compareGeneratedDeclarations> = [];\n let unreadable: string | undefined;\n if (generatedExists) {\n try {\n const collections = await loadCollections(path.resolve(process.cwd(), collectionsPath));\n const onDisk = fs.readFileSync(schemaFile, \"utf8\");\n stale = findLegacyForeignKeyNames(onDisk, collections);\n // The check the command's own summary promises, and the one it did\n // not make: render what these collections generate and compare it,\n // declaration by declaration, with the file on disk. Without this\n // the verdict rested entirely on `findLegacyForeignKeyNames`, which\n // looks for one historical naming defect — so a file the generator\n // visibly rewrites was reported as a match.\n const postgresCollections = relationalCollections(collections);\n if (postgresCollections.length > 0) {\n differences = compareGeneratedDeclarations(generateSchema(postgresCollections), onDisk);\n }\n } catch (err) {\n // Best-effort by design: a collections directory that will not load\n // is a real error, but it is one the boot reports far better than\n // this does. Said out loud all the same — this command used to exit\n // 0 in silence here, which is indistinguishable from a clean run.\n unreadable = err instanceof Error ? err.message : String(err);\n logger.debug(`schema stale: skipped (${unreadable})`);\n }\n }\n\n // The decision lives in `generated-schema-staleness.ts` so it can be tested:\n // this file uses `import.meta`, which the driver's jest suite cannot load,\n // and three of this command's four paths were silent because of it.\n const verdict = staleVerdict({ outputPath, generatedExists, stale, differences, unreadable, fix });\n\n for (const line of verdict.lines) {\n if (!line) out(\"\");\n else if (line.includes(\"⚠️\")) outWarn(chalk.yellow(line));\n else if (verdict.exitCode !== 0) outError(chalk.red(line));\n else if (line.includes(\"✓\")) out(chalk.green(line));\n else out(chalk.gray(line));\n }\n\n if (verdict.exitCode !== 0) process.exit(verdict.exitCode);\n if (!verdict.regenerate) return;\n\n await schemaCommand(\"generate\", [\"schema\", \"generate\", `--collections=${collectionsPath}`, `--output=${outputPath}`]);\n}\n\nasync function schemaCommand(subcommand: string, rawArgs: string[]): Promise<void> {\n // The same second line of defence `dbCommand` above carries, for the same\n // reason: this file is also its own CLI, spawned directly by\n // `resolvePluginCliScript` and executable on its own. Nothing here had a\n // `--help` case, so `schema generate --help` regenerated the schema and\n // `schema introspect --help` rewrote the collection files — a flag whose\n // entire job is to print text, overwriting authored source.\n //\n // Guarded by a real subcommand: the internal callers below re-enter this\n // function with a synthesised argv, and none of them can carry `--help`.\n if (subcommand && (rawArgs.includes(\"--help\") || rawArgs.includes(\"-h\"))) {\n out(\"\");\n out(chalk.bold(` rebase schema ${subcommand}`));\n out(chalk.gray(\" Run `rebase schema --help` for the full page — this is the driver's own entry point.\"));\n out(\"\");\n return;\n }\n\n if (subcommand === \"stale\") {\n await schemaStaleCommand(rawArgs);\n return;\n }\n\n if (subcommand === \"generate\") {\n const argsList = arg(\n {\n \"--collections\": String,\n \"--output\": String,\n \"--watch\": Boolean,\n \"-c\": \"--collections\",\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"-w\": \"--watch\"\n },\n {\n argv: rawArgs.slice(2), // db generate ... or schema generate ...\n permissive: true\n }\n );\n\n // Here we just invoke the local generate-drizzle-schema.ts since we are inside the postgresql-backend\n // If installed in node_modules, __cliDirname is node_modules/@rebasepro/server-postgres/dist or src.\n const generator = resolveChildScript(\"generate-drizzle-schema\");\n if (!generator.ok) {\n outError(chalk.red(childScriptError(\"schema generator\", generator.reason)));\n process.exit(1);\n }\n\n const collectionsPath = argsList[\"--collections\"] || path.join(\"..\", \"config\", \"collections\");\n const outputPath = argsList[\"--output\"] || path.join(\"src\", \"schema.generated.ts\");\n const watch = argsList[\"--watch\"] || false;\n\n out(\"\");\n out(chalk.bold(\" 🔧 Rebase Schema Generator\"));\n out(\"\");\n\n const cmdParts = [\n generator.bin,\n generator.script,\n `--collections=${collectionsPath}`,\n `--output=${outputPath}`\n ];\n if (watch) {\n cmdParts.push(\"--watch\");\n }\n\n try {\n await execa(cmdParts[0], cmdParts.slice(1), {\n cwd: process.cwd(),\n stdio: \"inherit\",\n env: { ...process.env as Record<string, string> }\n });\n } catch (err: unknown) {\n // Same contract as the DDL generator above: a child that exited\n // non-zero has already printed the cause on inherited stdio.\n if (typeof (err as { exitCode?: number }).exitCode === \"number\") {\n outError(chalk.red(\"✗ Drizzle schema generation failed — nothing was applied.\"));\n } else {\n outError(chalk.red(`✗ Failed to run schema generator: ${err instanceof Error ? err.message : String(err)}`));\n }\n process.exit(1);\n }\n } else if (subcommand === \"introspect\") {\n const argsList = arg(\n {\n \"--output\": String,\n \"--collections\": String,\n \"--force\": Boolean,\n \"--schema\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"-c\": \"--collections\",\n \"-f\": \"--force\"\n },\n {\n argv: rawArgs.slice(2),\n permissive: true\n }\n );\n\n const introspect = resolveChildScript(\"introspect-db\");\n if (!introspect.ok) {\n outError(chalk.red(childScriptError(\"introspection script\", introspect.reason)));\n process.exit(1);\n }\n\n const outputPath = argsList[\"--output\"] || argsList[\"--collections\"] || path.join(\"..\", \"config\", \"collections\");\n\n out(\"\");\n out(chalk.bold(\" 🔍 Rebase Schema Introspector\"));\n out(\"\");\n\n const cmdParts = [\n introspect.bin,\n introspect.script,\n `--output=${outputPath}`,\n ...(argsList[\"--force\"] ? [\"--force\"] : []),\n ...(argsList[\"--schema\"] ? [`--schema=${argsList[\"--schema\"]}`] : [])\n ];\n\n try {\n await execa(cmdParts[0], cmdParts.slice(1), {\n cwd: process.cwd(),\n stdio: \"inherit\",\n env: { ...process.env as Record<string, string> }\n });\n } catch (err: unknown) {\n outError(chalk.red(`✗ Failed to run schema introspector: ${err instanceof Error ? err.message : String(err)}`));\n process.exit(1);\n }\n } else {\n outError(chalk.red(\"Unknown schema command.\"));\n process.exit(1);\n }\n}\n\nasync function doctorPluginCommand(rawArgs: string[]): Promise<void> {\n const parsedArgs = arg(\n {\n \"--collections\": String,\n \"--schema\": String,\n \"--sdk\": String,\n \"--policies\": Boolean,\n \"-c\": \"--collections\",\n \"-s\": \"--schema\",\n \"-k\": \"--sdk\"\n },\n {\n argv: rawArgs.slice(1), // skip \"doctor\"\n permissive: true\n }\n );\n\n const doctor = resolveChildScript(\"doctor-cli\");\n if (!doctor.ok) {\n outError(chalk.red(childScriptError(\"doctor script\", doctor.reason)));\n process.exit(1);\n }\n\n const collectionsPath = parsedArgs[\"--collections\"] || path.join(\"..\", \"config\", \"collections\");\n const schemaPath = parsedArgs[\"--schema\"] || path.join(\"src\", \"schema.generated.ts\");\n const sdkPath = parsedArgs[\"--sdk\"] || path.join(\"..\", \"generated\", \"sdk\", \"database.types.ts\");\n\n const cmdParts = [\n doctor.bin,\n doctor.script,\n `--collections=${collectionsPath}`,\n `--schema=${schemaPath}`,\n `--sdk=${sdkPath}`,\n // Only the RLS checks: skips the schema/SDK diff, so it can run against\n // a deployed database as a CI gate.\n ...(parsedArgs[\"--policies\"] ? [\"--policies\"] : [])\n ];\n\n try {\n await execa(cmdParts[0], cmdParts.slice(1), {\n cwd: process.cwd(),\n stdio: \"inherit\",\n env: { ...process.env as Record<string, string> }\n });\n } catch {\n process.exit(1);\n }\n}\n\n\n// Entry point when called directly\nconst argv1Real = process.argv[1] ? fs.realpathSync(process.argv[1]) : \"\";\nif (import.meta.url === `file://${argv1Real}`) {\n // Drop node and script path\n runPluginCommand(process.argv.slice(2)).catch((error: unknown) => {\n reportCommandFailure(error);\n process.exit(1);\n });\n}\n"],"mappings":"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"}
|