@dbsp/cli 2.1.3 ā 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +570 -16
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/generate.ts","../src/commands/introspect.ts","../src/commands/migrate.ts","../src/migration-file.ts","../src/commands/push.ts","../src/ddl-executor.ts","../src/commands/repl.ts","../src/commands/verify.ts","../src/verifier.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * ARCH-002 Block 3: CLI Scaffold\n *\n * dbsp CLI - Schema-first code generation for db-semantic-planner.\n */\n\nimport { Command, CommanderError } from 'commander';\nimport { generateCommand } from './commands/generate.js';\nimport { introspectCommand } from './commands/introspect.js';\nimport { migrateCommand } from './commands/migrate.js';\nimport { pushCommand } from './commands/push.js';\nimport { replCommand } from './commands/repl.js';\nimport { verifyCommand } from './commands/verify.js';\n\nconst program = new Command();\n\nprogram\n\t.name('dbsp')\n\t.description('Schema-first code generation for db-semantic-planner')\n\t.version('0.0.1');\n\n// Register commands\nprogram.addCommand(generateCommand);\nprogram.addCommand(introspectCommand);\nprogram.addCommand(migrateCommand);\nprogram.addCommand(pushCommand);\nprogram.addCommand(replCommand);\nprogram.addCommand(verifyCommand);\n\n// CC-15: Intercept Commander parse errors so --json commands receive a JSON\n// error object on stdout instead of a plain-text usage message.\nprogram.exitOverride();\n\ntry {\n\tprogram.parse();\n} catch (err) {\n\t// Commander throws CommanderError for --help, --version, and parse errors.\n\t// Exit 0 for informational outputs (help/version); only exit 1 for real errors.\n\tif (err instanceof CommanderError && err.exitCode === 0) {\n\t\tprocess.exit(0);\n\t}\n\tconst message = err instanceof Error ? err.message : 'Command parse error';\n\tif (process.argv.includes('--json')) {\n\t\tconsole.log(JSON.stringify({ status: 'error', error: message }, null, 2));\n\t} else {\n\t\tconsole.error(`ā ${message}`);\n\t}\n\tprocess.exit(1);\n}\n","/**\n * ARCH-002 Block 3+4+5: Generate Command\n * CLI-DDL: Added DDL generation target\n * ARCH-005: Migrated to schema() API, removed legacy generators\n *\n * dbsp generate <target> - Generate code from schema.\n *\n * Targets:\n * - ddl: Generate SQL DDL (CREATE TABLE statements)\n *\n * Deprecated targets (removed in ARCH-005):\n * - manifest: Removed legacy manifest generator\n * - kysely: Removed legacy Kysely generator\n */\n\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport type { DbCasing } from '@dbsp/types';\nimport { Command } from 'commander';\nimport { loadSchema, loadSchemaFromCwd } from '../utils/schema-loader.js';\n\nexport type GenerateCasingOption = 'snake' | 'camel' | 'none';\n\nexport const generateCommand = new Command('generate')\n\t.description('Generate code from schema')\n\t.argument('<target>', 'Target to generate: ddl')\n\t.option('-s, --schema <path>', 'Path to schema file (default: auto-detect)')\n\t.option('-o, --out <dir>', 'Output directory (default: ./generated/<target>)')\n\t.option('--output <dir>', 'Output directory (alias for --out)')\n\t.option('--drop', 'Include DROP TABLE IF EXISTS statements (ddl only)')\n\t.option('--schema-name <name>', 'Database schema name (ddl only)')\n\t.option(\n\t\t'--dialect <name>',\n\t\t'Database dialect: postgresql | mysql | sqlite | mssql (default: postgresql)',\n\t)\n\t.option(\n\t\t'--casing <type>',\n\t\t'Column naming: snake | camel | none (default: based on dialect)',\n\t)\n\t.action(\n\t\tasync (\n\t\t\ttarget: string,\n\t\t\toptions: {\n\t\t\t\tschema?: string;\n\t\t\t\tout?: string;\n\t\t\t\toutput?: string;\n\t\t\t\tdrop?: boolean;\n\t\t\t\tschemaName?: string;\n\t\t\t\tdialect?: string;\n\t\t\t\tcasing?: GenerateCasingOption;\n\t\t\t},\n\t\t) => {\n\t\t\ttry {\n\t\t\t\t// Reject the target BEFORE loading the schema: loading it executes the\n\t\t\t\t// user's schema module, and there is no reason to run their code for a\n\t\t\t\t// target we are going to refuse anyway.\n\t\t\t\tif (target === 'manifest' || target === 'kysely') {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Target '${target}' has been removed. ` +\n\t\t\t\t\t\t\t`Use 'ddl' for SQL generation, or the 'introspect' command to generate a schema file.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (target !== 'ddl') {\n\t\t\t\t\tthrow new Error(`Unknown target: ${target}. Available targets: ddl`);\n\t\t\t\t}\n\n\t\t\t\t// Load schema (ARCH-005: only schema() format supported)\n\t\t\t\tlet schema: Awaited<ReturnType<typeof loadSchema>>;\n\t\t\t\tlet schemaPath: string;\n\n\t\t\t\tif (options.schema) {\n\t\t\t\t\tschema = await loadSchema(options.schema);\n\t\t\t\t\tschemaPath = options.schema;\n\t\t\t\t} else {\n\t\t\t\t\tconst result = await loadSchemaFromCwd();\n\t\t\t\t\tschema = result.schema;\n\t\t\t\t\tschemaPath = result.path;\n\t\t\t\t}\n\n\t\t\t\t// For DDL without --output, we output to stdout so use stderr for info\n\t\t\t\tconst outputPath = options.out ?? options.output;\n\t\t\t\tconst useStdout = target === 'ddl' && !outputPath;\n\t\t\t\tconst log = useStdout ? console.error : console.log;\n\n\t\t\t\tlog(`š Loaded schema from: ${schemaPath}`);\n\n\t\t\t\t// Validate dialect option\n\t\t\t\tconst dialect = options.dialect ?? 'postgresql';\n\t\t\t\tif (!isDialectSupported(dialect)) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`ā ļø Warning: Only 'postgresql' dialect is currently supported. Using postgresql.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Generate based on target\n\t\t\t\tswitch (target) {\n\t\t\t\t\tcase 'ddl': {\n\t\t\t\t\t\t// Determine casing: explicit option > schema export > dialect default.\n\t\t\t\t\t\tconst dbCasing =\n\t\t\t\t\t\t\tmapCasingToDbCasing(options.casing) ??\n\t\t\t\t\t\t\tschema.dbCasing ??\n\t\t\t\t\t\t\t('snake_case' as const);\n\t\t\t\t\t\tconst casingLabel = formatGenerateCasingLabel(dbCasing);\n\n\t\t\t\t\t\t// Import adapter from adapter-pgsql (compile-only, no DB connection needed)\n\t\t\t\t\t\tconst { createPgsqlCompileOnlyAdapter } = await import(\n\t\t\t\t\t\t\t'@dbsp/adapter-pgsql'\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst adapter = createPgsqlCompileOnlyAdapter({\n\t\t\t\t\t\t\tdbCasing,\n\t\t\t\t\t\t\t...(options.schemaName ? { schemaName: options.schemaName } : {}),\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// ARCH-005: Use schema.model directly (already ModelIR)\n\t\t\t\t\t\t\tconst ddlStatements = adapter.generateDDL(schema.model, {\n\t\t\t\t\t\t\t\t...(options.drop !== undefined && {\n\t\t\t\t\t\t\t\t\tincludeDropStatements: options.drop,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tconst ddlContent = ddlStatements.join('\\n\\n');\n\t\t\t\t\t\t\tconst outputPath = options.out ?? options.output;\n\n\t\t\t\t\t\t\tif (outputPath) {\n\t\t\t\t\t\t\t\t// Write to file if --output is specified\n\t\t\t\t\t\t\t\tconst outPath = outputPath.endsWith('.sql')\n\t\t\t\t\t\t\t\t\t? resolve(process.cwd(), outputPath)\n\t\t\t\t\t\t\t\t\t: resolve(process.cwd(), outputPath, 'schema.sql');\n\n\t\t\t\t\t\t\t\tmkdirSync(dirname(outPath), { recursive: true });\n\t\t\t\t\t\t\t\twriteFileSync(outPath, ddlContent, 'utf-8');\n\n\t\t\t\t\t\t\t\tconsole.log(`ā
Generated DDL: ${outPath}`);\n\t\t\t\t\t\t\t\tconsole.log(` Tables: ${schema.tableNames.length}`);\n\t\t\t\t\t\t\t\tconsole.log(` Statements: ${ddlStatements.length}`);\n\t\t\t\t\t\t\t\tconsole.log(` Casing: ${casingLabel}`);\n\t\t\t\t\t\t\t\tif (options.drop) {\n\t\t\t\t\t\t\t\t\tconsole.log(` Includes DROP statements`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (options.schemaName) {\n\t\t\t\t\t\t\t\t\tconsole.log(` Schema: ${options.schemaName}`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Output DDL to stdout (for piping)\n\t\t\t\t\t\t\t\t// Info messages (schema loaded) went to stderr\n\t\t\t\t\t\t\t\tconsole.log(ddlContent);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tconsole.error(`ā ${message}`);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nexport function isDialectSupported(dialect: string): dialect is 'postgresql' {\n\treturn dialect === 'postgresql';\n}\n\nexport function mapCasingToDbCasing(\n\tcasing: GenerateCasingOption | undefined,\n): DbCasing | undefined {\n\tswitch (casing) {\n\t\tcase 'snake':\n\t\t\treturn 'snake_case';\n\t\tcase 'camel':\n\t\t\treturn 'camelCase';\n\t\tcase 'none':\n\t\t\treturn 'preserve';\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nfunction formatGenerateCasingLabel(\n\tdbCasing: DbCasing,\n): 'snake' | 'camel' | 'none' {\n\tswitch (dbCasing) {\n\t\tcase 'snake_case':\n\t\t\treturn 'snake';\n\t\tcase 'camelCase':\n\t\t\treturn 'camel';\n\t\tcase 'preserve':\n\t\t\treturn 'none';\n\t}\n}\n","/**\n * CLI-DDL: Introspect Command\n *\n * dbsp introspect - Generate schema.ts from database introspection.\n */\n\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { Command } from 'commander';\nimport {\n\tgenerateSchemaFileWithDiagnostics,\n\ttype SchemaCodegenOptions,\n} from '../generators/schema-codegen.js';\nimport { createDbConnection, redactDbUrl } from '../utils/db-utils.js';\n\nfunction uniqueWarnings(warnings: readonly string[]): string[] {\n\tconst seen = new Set<string>();\n\tconst unique: string[] = [];\n\tfor (const warning of warnings) {\n\t\tif (seen.has(warning)) continue;\n\t\tseen.add(warning);\n\t\tunique.push(warning);\n\t}\n\treturn unique;\n}\n\nfunction reportWarnings(warnings: readonly string[]): void {\n\tfor (const warning of warnings) {\n\t\tconsole.log(` ā ļø ${warning}`);\n\t}\n}\n\nexport const introspectCommand = new Command('introspect')\n\t.description('Generate schema.ts from database introspection')\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('-o, --out <file>', 'Output schema file', './dbsp.schema.ts')\n\t.option('--schema-name <name>', 'Database schema name', 'public')\n\t.option(\n\t\t'--exclude <patterns>',\n\t\t'Tables to exclude (comma-separated glob patterns)',\n\t\t'_migrations,_prisma*,pg_*',\n\t)\n\t.option('--include <patterns>', 'Tables to include (comma-separated)')\n\t.option('--no-db-type-comments', 'Omit original DB type comments')\n\t.option(\n\t\t'--db-casing <casing>',\n\t\t'Database column casing (snake_case ā camelCase in generated code)',\n\t\t'snake_case',\n\t)\n\t.action(\n\t\tasync (options: {\n\t\t\tdb: string;\n\t\t\tout: string;\n\t\t\tschemaName: string;\n\t\t\texclude: string;\n\t\t\tinclude?: string;\n\t\t\tdbTypeComments: boolean;\n\t\t\tdbCasing: 'snake_case' | 'camelCase' | 'preserve';\n\t\t}) => {\n\t\t\tconst redactedUrl = redactDbUrl(options.db);\n\n\t\t\tconsole.log(`š Introspecting database: ${redactedUrl}`);\n\t\t\tconsole.log(` Schema: ${options.schemaName}`);\n\t\t\tif (options.exclude) {\n\t\t\t\tconsole.log(` Excluding: ${options.exclude}`);\n\t\t\t}\n\t\t\tconsole.log('');\n\n\t\t\ttry {\n\t\t\t\t// Connect to database\n\t\t\t\tconst { pool } = await createDbConnection(options.db);\n\n\t\t\t\ttry {\n\t\t\t\t\t// Import introspect from adapter-pgsql\n\t\t\t\t\tconst { introspect } = await import('@dbsp/adapter-pgsql');\n\n\t\t\t\t\t// Build introspection options from CLI flags\n\t\t\t\t\tconst excludePatterns = options.exclude\n\t\t\t\t\t\t? options.exclude.split(',').map((s) => s.trim())\n\t\t\t\t\t\t: undefined;\n\t\t\t\t\tconst includePatterns = options.include\n\t\t\t\t\t\t? options.include.split(',').map((s) => s.trim())\n\t\t\t\t\t\t: undefined;\n\n\t\t\t\t\t// Introspect the database directly (returns IntrospectedModelIR)\n\t\t\t\t\tconst model = await introspect(pool, {\n\t\t\t\t\t\tschema: options.schemaName,\n\t\t\t\t\t\t...(excludePatterns ? { exclude: excludePatterns } : {}),\n\t\t\t\t\t\t...(includePatterns ? { include: includePatterns } : {}),\n\t\t\t\t\t});\n\n\t\t\t\t\t// Report what we found\n\t\t\t\t\tconst tableCount = model.tables.size;\n\t\t\t\t\tconst relationCount = model.relations.size;\n\t\t\t\t\tconst hierarchyCount = model.hierarchies?.length ?? 0;\n\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`š Found ${tableCount} tables, ${relationCount} relations, ${hierarchyCount} hierarchies`,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Generate schema file ā pass metadata from introspection\n\t\t\t\t\tconst codegenOptions: SchemaCodegenOptions = {\n\t\t\t\t\t\tsourceUrl: options.db,\n\t\t\t\t\t\tincludeDbTypeComments: options.dbTypeComments,\n\t\t\t\t\t\tintrospectedAt: model.introspectedAt,\n\t\t\t\t\t\tdbCasing: options.dbCasing,\n\t\t\t\t\t};\n\n\t\t\t\t\tconst generated = generateSchemaFileWithDiagnostics(\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tcodegenOptions,\n\t\t\t\t\t);\n\t\t\t\t\tconst warnings = uniqueWarnings(generated.warnings);\n\t\t\t\t\tif (warnings.length > 0) {\n\t\t\t\t\t\treportWarnings(warnings);\n\t\t\t\t\t}\n\t\t\t\t\tconsole.log('');\n\n\t\t\t\t\t// Write output file\n\t\t\t\t\tconst outPath = resolve(process.cwd(), options.out);\n\t\t\t\t\tmkdirSync(dirname(outPath), { recursive: true });\n\t\t\t\t\twriteFileSync(outPath, generated.code, 'utf-8');\n\n\t\t\t\t\tconsole.log(`ā
Generated schema: ${outPath}`);\n\t\t\t\t\tconsole.log(` Tables: ${tableCount}`);\n\t\t\t\t\tconsole.log(` Relations: ${relationCount}`);\n\t\t\t\t} finally {\n\t\t\t\t\t// Close database connection\n\t\t\t\t\tawait pool.end();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tconsole.error(`ā ${message}`);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n","/**\n * Migrate Command ā Migration Infrastructure\n *\n * dbsp migrate dev - Generate migration from schema diff\n * dbsp migrate apply - Apply pending migrations\n * dbsp migrate rollback - Roll back applied migrations\n * dbsp migrate status - Show migration status\n */\n\nimport {\n\tcomparePgsqlDatabaseSchema,\n\tcreatePgsqlAdapter,\n\tensureMigrationsTable,\n\tgenerateMigrationFile,\n\tgenerateMigrationSQL,\n\tgetAppliedMigrations,\n\tgetNextSchemaVersion,\n\tisDestructiveDown,\n\ttype MigrationRecord,\n\tparseMigrationFile,\n\trecordMigration,\n\tremoveMigrationRecord,\n\twithMigrationLock,\n} from '@dbsp/adapter-pgsql';\nimport { Command } from 'commander';\nimport type { Pool, PoolClient } from 'pg';\nimport {\n\tDEFAULT_MIGRATIONS_DIR,\n\tgenerateMigrationFilename,\n\ttype MigrationFile,\n\tscanMigrationFiles,\n\twriteMigrationFile,\n} from '../migration-file.js';\nimport { createDbConnection, redactDbUrl } from '../utils/db-utils.js';\nimport { loadSchema } from '../utils/schema-loader.js';\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Typed error for migration failures.\n * Distinguishes user-facing errors (validation, logic) from unexpected errors.\n */\nexport class MigrationError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'MigrationError';\n\t}\n}\n\n/**\n * Sanitize a pg error for user-facing output.\n *\n * PostgreSQL errors may carry schema/table/row details in their message text.\n * For pg errors (identifiable by SQLSTATE `.code`), we emit a sanitized message\n * keyed only by the SQLSTATE code. The raw message is available via DEBUG=dbsp.\n *\n * @param err - Any caught value\n * @returns An Error instance safe to display to the user\n */\nexport function sanitizePgError(err: unknown): Error {\n\tif (err instanceof Error) {\n\t\t// pg errors carry a SQLSTATE `.code` property\n\t\tconst code = (err as Error & { code?: string }).code;\n\t\tif (typeof code === 'string' && /^[0-9A-Z]{5}$/.test(code)) {\n\t\t\tif (process.env.DEBUG?.includes('dbsp')) {\n\t\t\t\tconsole.error(`[DEBUG] pg error detail: ${err.message}`);\n\t\t\t}\n\t\t\treturn new MigrationError(`Migration failed: database error ${code}`);\n\t\t}\n\t\treturn err;\n\t}\n\treturn new Error(String(err));\n}\n\n/**\n * DRY lifecycle wrapper: create pool ā run fn ā end pool on success or error.\n * Replaces the repeated try { ... } finally { pool.end() } pattern across commands.\n *\n * process.exit is called OUTSIDE the pool lifecycle so the lock-holding client\n * (from withMigrationLock) is always released before the process terminates.\n */\nexport async function withMigratePool<T>(\n\tdbUrl: string,\n\tfn: (pool: Pool) => Promise<T>,\n): Promise<T> {\n\tconst { pool } = await createDbConnection(dbUrl);\n\ttry {\n\t\treturn await fn(pool);\n\t} finally {\n\t\tlet endError: unknown;\n\t\ttry {\n\t\t\tawait pool.end();\n\t\t} catch (e) {\n\t\t\tendError = e;\n\t\t}\n\t\tif (endError !== undefined) {\n\t\t\t// Cleanup failure is non-fatal ā log it but don't mask the original error\n\t\t\tconsole.error(\n\t\t\t\t`Warning: pool.end() failed: ${endError instanceof Error ? endError.message : String(endError)}`,\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Top-level error handler for migrate commands.\n * Ensures process.exit is only called AFTER pool cleanup (via withMigratePool).\n */\nasync function runMigrateAction(fn: () => Promise<void>): Promise<void> {\n\ttry {\n\t\tawait fn();\n\t} catch (error) {\n\t\tif (error instanceof Error) {\n\t\t\tconsole.error(`ā Error: ${error.message}`);\n\t\t} else {\n\t\t\tconsole.error('ā Unknown error occurred');\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n\n/**\n * Returns true if a migration statement contains at least one executable SQL\n * line (non-empty, not a comment). Statements that consist entirely of blank\n * lines and `--` comment lines are skipped; statements that begin with a\n * comment header but also contain real SQL are kept (PostgreSQL ignores the\n * comment, so the header is harmless and preserves intent).\n */\nexport function hasExecutableSql(stmt: string): boolean {\n\treturn stmt.split('\\n').some((line) => {\n\t\tconst t = line.trim();\n\t\treturn t.length > 0 && !t.startsWith('--');\n\t});\n}\n\nexport interface ApplyOptions {\n\tdb: string;\n\tdir: string;\n\tdryRun?: boolean;\n}\n\nexport interface RollbackOptions {\n\tcount: number;\n\tdb: string;\n\tdir: string;\n\tforce?: boolean;\n}\n\nexport interface MigrateDeps {\n\twithMigratePool?: <T>(\n\t\tdbUrl: string,\n\t\tfn: (pool: Pool) => Promise<T>,\n\t) => Promise<T>;\n\tensureMigrationsTable?: (pool: Pool) => Promise<void>;\n\twithMigrationLock?: <T>(\n\t\tpool: Pool,\n\t\tfn: (client: PoolClient) => Promise<T>,\n\t) => Promise<T>;\n\tgetAppliedMigrations?: (pool: Pool) => Promise<readonly MigrationRecord[]>;\n\tscanMigrationFiles?: (dir: string) => readonly MigrationFile[];\n\tparseMigrationFile?: typeof parseMigrationFile;\n\tgetNextSchemaVersion?: (pool: Pool) => Promise<number>;\n\trecordMigration?: (\n\t\tpool: Pool,\n\t\tname: string,\n\t\tchecksum: string,\n\t\tschemaVersion: number,\n\t\tdestructive: boolean,\n\t) => Promise<void>;\n\tremoveMigrationRecord?: (pool: Pool, name: string) => Promise<void>;\n\tisDestructiveDown?: (downStatements: readonly string[]) => boolean;\n}\n\nconst defaultMigrateDeps: Required<MigrateDeps> = {\n\twithMigratePool,\n\tensureMigrationsTable,\n\twithMigrationLock,\n\tgetAppliedMigrations,\n\tscanMigrationFiles,\n\tparseMigrationFile,\n\tgetNextSchemaVersion,\n\trecordMigration,\n\tremoveMigrationRecord,\n\tisDestructiveDown,\n};\n\nfunction resolveMigrateDeps(deps?: MigrateDeps): Required<MigrateDeps> {\n\treturn { ...defaultMigrateDeps, ...deps };\n}\n\nexport async function runApply(\n\toptions: ApplyOptions,\n\tdeps?: MigrateDeps,\n): Promise<void> {\n\tconst d = resolveMigrateDeps(deps);\n\n\tconsole.log('š Applying migrations');\n\tconsole.log(` Database: ${redactDbUrl(options.db)}`);\n\tconsole.log(` Directory: ${options.dir}`);\n\tconsole.log('');\n\n\tawait d.withMigratePool(options.db, async (pool) => {\n\t\t// Ensure tracking table exists before acquiring lock\n\t\tawait d.ensureMigrationsTable(pool);\n\n\t\tawait d.withMigrationLock(pool, async (client) => {\n\t\t\t// Get applied migrations on the lock-holding client\n\t\t\tconst applied = await d.getAppliedMigrations(client as unknown as Pool);\n\t\t\tconst appliedMap = new Map(applied.map((m) => [m.name, m.checksum]));\n\n\t\t\t// Scan migration files\n\t\t\tconst files = d.scanMigrationFiles(options.dir);\n\n\t\t\tif (files.length === 0) {\n\t\t\t\tconsole.log(`No migration files found in ${options.dir}`);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Validate checksums for already-applied migrations\n\t\t\tfor (const file of files) {\n\t\t\t\tconst existingChecksum = appliedMap.get(file.name);\n\t\t\t\tif (\n\t\t\t\t\texistingChecksum !== undefined &&\n\t\t\t\t\texistingChecksum !== file.checksum\n\t\t\t\t) {\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t`Checksum mismatch for ${file.name}\\n` +\n\t\t\t\t\t\t\t` Expected: ${existingChecksum}\\n` +\n\t\t\t\t\t\t\t` Got: ${file.checksum}\\n` +\n\t\t\t\t\t\t\t'\\nMigration file has been tampered with after being applied.',\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Find pending migrations\n\t\t\tconst pending = files.filter((f) => !appliedMap.has(f.name));\n\n\t\t\tif (pending.length === 0) {\n\t\t\t\tconsole.log('ā
All migrations already applied.');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (options.dryRun) {\n\t\t\t\tconsole.log(`${pending.length} pending migration(s):`);\n\t\t\t\tfor (const file of pending) {\n\t\t\t\t\tconsole.log(` - ${file.name}`);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Apply each pending migration atomically (DDL + record in one transaction)\n\t\t\tlet appliedCount = 0;\n\t\t\tfor (const file of pending) {\n\t\t\t\tconsole.log(` Applying: ${file.name}...`);\n\n\t\t\t\t// Parse UP section from file\n\t\t\t\tconst parsed = d.parseMigrationFile(file.content);\n\t\t\t\tconst statements = parsed.upStatements.filter(hasExecutableSql);\n\n\t\t\t\t// Determine version and destructive flag before the transaction\n\t\t\t\t// (read from the lock-held client so we see a consistent view)\n\t\t\t\tconst version = await d.getNextSchemaVersion(client as unknown as Pool);\n\t\t\t\tconst destructive = parsed.destructive === true;\n\n\t\t\t\t// Atomic: DDL + record in ONE transaction on the lock-holding client\n\t\t\t\ttry {\n\t\t\t\t\tawait client.query('BEGIN');\n\n\t\t\t\t\tfor (const stmt of statements) {\n\t\t\t\t\t\tawait client.query(stmt);\n\t\t\t\t\t}\n\n\t\t\t\t\tawait d.recordMigration(\n\t\t\t\t\t\tclient as unknown as Pool,\n\t\t\t\t\t\tfile.name,\n\t\t\t\t\t\tfile.checksum,\n\t\t\t\t\t\tversion,\n\t\t\t\t\t\tdestructive,\n\t\t\t\t\t);\n\n\t\t\t\t\tawait client.query('COMMIT');\n\t\t\t\t} catch (applyError) {\n\t\t\t\t\tlet rollbackError: unknown;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait client.query('ROLLBACK');\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\trollbackError = e;\n\t\t\t\t\t}\n\t\t\t\t\tconst primary = sanitizePgError(applyError);\n\t\t\t\t\tif (rollbackError !== undefined) {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t` Note: rollback also failed: ${sanitizePgError(rollbackError).message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tthrow primary;\n\t\t\t\t}\n\n\t\t\t\tappliedCount++;\n\t\t\t\tconsole.log(` ā
Applied: ${file.name}`);\n\t\t\t}\n\n\t\t\tconsole.log(`\\nā
${appliedCount} migration(s) applied successfully.`);\n\t\t});\n\t});\n}\n\nexport async function runRollback(\n\toptions: RollbackOptions,\n\tdeps?: MigrateDeps,\n): Promise<void> {\n\tconst d = resolveMigrateDeps(deps);\n\n\tconsole.log(`āŖ Rolling back ${options.count} migration(s)`);\n\tconsole.log(` Database: ${redactDbUrl(options.db)}`);\n\tconsole.log(` Directory: ${options.dir}`);\n\tconsole.log('');\n\n\tawait d.withMigratePool(options.db, async (pool) => {\n\t\tawait d.ensureMigrationsTable(pool);\n\n\t\tawait d.withMigrationLock(pool, async (client) => {\n\t\t\t// Get applied migrations on the lock-holding client\n\t\t\tconst applied = await d.getAppliedMigrations(client as unknown as Pool);\n\t\t\tconst sortedDesc = [...applied].sort((a, b) =>\n\t\t\t\tb.name.localeCompare(a.name),\n\t\t\t);\n\n\t\t\t// SC-18: Validate count\n\t\t\tif (options.count > sortedDesc.length) {\n\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t`Cannot roll back ${options.count} migration(s) ā only ${sortedDesc.length} applied`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst toRollback = sortedDesc.slice(0, options.count);\n\n\t\t\t// Load migration files from disk\n\t\t\tconst files = d.scanMigrationFiles(options.dir);\n\t\t\tconst fileMap = new Map(files.map((f) => [f.name, f]));\n\n\t\t\tlet rolledBack = 0;\n\t\t\tfor (const record of toRollback) {\n\t\t\t\tconst file = fileMap.get(record.name);\n\t\t\t\tif (!file) {\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t`Migration file not found on disk: ${record.name}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// SC-17: Verify checksum\n\t\t\t\tif (file.checksum !== record.checksum) {\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t`Checksum mismatch for ${record.name}\\n` +\n\t\t\t\t\t\t\t` Expected: ${record.checksum}\\n` +\n\t\t\t\t\t\t\t` Got: ${file.checksum}\\n` +\n\t\t\t\t\t\t\t'\\nMigration file has been modified since it was applied.',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Parse DOWN section\n\t\t\t\tconst parsed = d.parseMigrationFile(file.content);\n\n\t\t\t\t// SC-10/ERR-01: No DOWN section\n\t\t\t\tif (!parsed.hasDown) {\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t`Migration ${record.name} has no DOWN section\\n` +\n\t\t\t\t\t\t\t' Cannot roll back a migration without a DOWN section.',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// SC-11/ERR-04: Empty DOWN section\n\t\t\t\tconst downStmts = parsed.downStatements.filter(hasExecutableSql);\n\t\t\t\tif (downStmts.length === 0 && !options.force) {\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t`Migration ${record.name} has an empty DOWN section\\n` +\n\t\t\t\t\t\t\t' Use --force to roll back anyway.',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// SC-19: Metadata-driven destructive rollback guard\n\t\t\t\tconst safeHeaderContradictedByDown =\n\t\t\t\t\tparsed.destructive === false && d.isDestructiveDown(downStmts);\n\t\t\t\tif (\n\t\t\t\t\t(parsed.destructive !== false || safeHeaderContradictedByDown) &&\n\t\t\t\t\t!options.force\n\t\t\t\t) {\n\t\t\t\t\tif (parsed.destructive === true) {\n\t\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t\t`Migration ${record.name} has destructive DOWN operations\\n` +\n\t\t\t\t\t\t\t\t' Use --force to proceed with destructive rollback.',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (safeHeaderContradictedByDown) {\n\t\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t\t`Migration ${record.name} is marked non-destructive but its DOWN section contains an obvious destructive statement\\n` +\n\t\t\t\t\t\t\t\t' Re-generate the migration with accurate dbsp metadata or pass --force.',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t`Migration ${record.name} is unmarked or legacy\\n` +\n\t\t\t\t\t\t\t' Re-generate the migration with dbsp metadata or pass --force.',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Atomic: DOWN SQL + remove record in ONE transaction on the lock-holding client\n\t\t\t\tif (downStmts.length > 0 || options.force) {\n\t\t\t\t\tconsole.log(` Rolling back: ${record.name}...`);\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tawait client.query('BEGIN');\n\n\t\t\t\t\tfor (const stmt of downStmts) {\n\t\t\t\t\t\tawait client.query(stmt);\n\t\t\t\t\t}\n\n\t\t\t\t\tawait d.removeMigrationRecord(client as unknown as Pool, record.name);\n\n\t\t\t\t\tawait client.query('COMMIT');\n\t\t\t\t} catch (rollbackError) {\n\t\t\t\t\tlet rollbackCleanupError: unknown;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait client.query('ROLLBACK');\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\trollbackCleanupError = e;\n\t\t\t\t\t}\n\t\t\t\t\tconst primary = sanitizePgError(rollbackError);\n\t\t\t\t\tif (rollbackCleanupError !== undefined) {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t` Note: rollback also failed: ${sanitizePgError(rollbackCleanupError).message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tthrow primary;\n\t\t\t\t}\n\n\t\t\t\trolledBack++;\n\t\t\t\tconsole.log(` ā
Rolled back: ${record.name}`);\n\t\t\t}\n\n\t\t\tconsole.log(`\\nā
${rolledBack} migration(s) rolled back successfully.`);\n\t\t});\n\t});\n}\n\nfunction runRollbackCommand(\n\tcountArg: string,\n\toptions: { db: string; dir: string; force?: boolean },\n): Promise<void> {\n\tconst count = Number.parseInt(countArg, 10);\n\tif (Number.isNaN(count) || count < 1) {\n\t\tconsole.error('ā Count must be a positive integer');\n\t\tprocess.exit(1);\n\t}\n\n\treturn runMigrateAction(async () => {\n\t\tawait runRollback({ count, ...options });\n\t});\n}\n\n// ============================================================================\n// Subcommands\n// ============================================================================\n\nconst devCommand = new Command('dev')\n\t.description('Generate a migration from schema changes')\n\t.option(\n\t\t'-s, --schema <path>',\n\t\t'Path to schema file (default: dbsp.schema.ts)',\n\t)\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--schema-name <name>', 'Database schema name (default: public)')\n\t.option('--dir <path>', 'Migrations directory', DEFAULT_MIGRATIONS_DIR)\n\t.option('-n, --name <description>', 'Migration description', 'migration')\n\t.option('--allow-destructive', 'Include destructive changes (drops)')\n\t.action(\n\t\t(options: {\n\t\t\tschema?: string;\n\t\t\tdb: string;\n\t\t\tschemaName?: string;\n\t\t\tdir: string;\n\t\t\tname: string;\n\t\t\tallowDestructive?: boolean;\n\t\t}) =>\n\t\t\trunMigrateAction(async () => {\n\t\t\t\tconst schemaPath = options.schema ?? 'dbsp.schema.ts';\n\n\t\t\t\tconsole.log(`š Generating migration: ${schemaPath}`);\n\t\t\t\tconsole.log(` Database: ${redactDbUrl(options.db)}`);\n\t\t\t\tconsole.log('');\n\n\t\t\t\tconst loaded = await loadSchema(schemaPath);\n\t\t\t\tconst schemaModel = loaded.model;\n\n\t\t\t\tawait withMigratePool(options.db, async (pool) => {\n\t\t\t\t\tconst adapter = createPgsqlAdapter(pool);\n\t\t\t\t\tconst diff = await comparePgsqlDatabaseSchema(adapter, schemaModel, {\n\t\t\t\t\t\t...(options.schemaName ? { schema: options.schemaName } : {}),\n\t\t\t\t\t\t...(loaded.dbCasing ? { dbCasing: loaded.dbCasing } : {}),\n\t\t\t\t\t\tonWarning: (message) => console.warn(`ā ļø ${message}`),\n\t\t\t\t\t});\n\n\t\t\t\t\tif (diff.changes.length === 0) {\n\t\t\t\t\t\tconsole.log('ā
No changes detected ā database matches schema.');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check for destructive changes\n\t\t\t\t\tif (diff.hasDestructive && !options.allowDestructive) {\n\t\t\t\t\t\tconst destructive = diff.changes.filter((c) => c.destructive);\n\t\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t\t`${destructive.length} destructive change(s) detected:\\n` +\n\t\t\t\t\t\t\t\tdestructive.map((c) => ` - ${c.details}`).join('\\n') +\n\t\t\t\t\t\t\t\t'\\n\\nUse --allow-destructive to include these changes.',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst sqlOptions = {\n\t\t\t\t\t\tincludeDestructive: options.allowDestructive ?? false,\n\t\t\t\t\t\t...(options.schemaName ? { schemaName: options.schemaName } : {}),\n\t\t\t\t\t};\n\n\t\t\t\t\tconst statements = generateMigrationSQL(diff, sqlOptions);\n\n\t\t\t\t\tif (statements.length === 0) {\n\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t'ā
No migration needed ā all changes are non-actionable.',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Generate migration file with UP + DOWN sections\n\t\t\t\t\tconst existingFiles = scanMigrationFiles(options.dir).map(\n\t\t\t\t\t\t(f) => f.name,\n\t\t\t\t\t);\n\t\t\t\t\tconst filename = generateMigrationFilename(\n\t\t\t\t\t\texistingFiles,\n\t\t\t\t\t\toptions.name,\n\t\t\t\t\t);\n\t\t\t\t\tconst content = generateMigrationFile(diff, {\n\t\t\t\t\t\t...sqlOptions,\n\t\t\t\t\t\tname: filename,\n\t\t\t\t\t});\n\n\t\t\t\t\tconst file = writeMigrationFile(options.dir, filename, content);\n\n\t\t\t\t\tconsole.log(`ā
Migration created: ${file.path}`);\n\t\t\t\t\tconsole.log(` Statements: ${statements.length}`);\n\t\t\t\t\tconsole.log(` Checksum: ${file.checksum.slice(0, 12)}...`);\n\t\t\t\t});\n\t\t\t}),\n\t);\n\nconst applyCommand = new Command('apply')\n\t.description('Apply pending migrations')\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--dir <path>', 'Migrations directory', DEFAULT_MIGRATIONS_DIR)\n\t.option('--dry-run', 'Show pending migrations without applying')\n\t.action((options: ApplyOptions) =>\n\t\trunMigrateAction(async () => {\n\t\t\tawait runApply(options);\n\t\t}),\n\t);\n\nconst rollbackCommand = new Command('rollback')\n\t.description('Roll back applied migrations')\n\t.argument('<count>', 'Number of migrations to roll back')\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--dir <path>', 'Migrations directory', DEFAULT_MIGRATIONS_DIR)\n\t.option('--force', 'Force rollback of destructive or empty DOWN migrations')\n\t.action(runRollbackCommand);\n\nconst statusCommand = new Command('status')\n\t.description('Show migration status')\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--dir <path>', 'Migrations directory', DEFAULT_MIGRATIONS_DIR)\n\t.option('--json', 'Output as JSON')\n\t.action((options: { db: string; dir: string; json?: boolean }) =>\n\t\trunMigrateAction(async () => {\n\t\t\tawait withMigratePool(options.db, async (pool) => {\n\t\t\t\tawait ensureMigrationsTable(pool);\n\n\t\t\t\tconst applied = await getAppliedMigrations(pool);\n\t\t\t\tconst appliedMap = new Map(applied.map((m) => [m.name, m]));\n\n\t\t\t\tconst files = scanMigrationFiles(options.dir);\n\n\t\t\t\tconst statuses: Array<{\n\t\t\t\t\tname: string;\n\t\t\t\t\tstatus: 'pending' | 'applied' | 'checksum_mismatch' | 'missing_file';\n\t\t\t\t\tappliedAt?: Date;\n\t\t\t\t}> = files.map((file) => {\n\t\t\t\t\tconst record = appliedMap.get(file.name);\n\t\t\t\t\tif (record === undefined) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tname: file.name,\n\t\t\t\t\t\t\tstatus: 'pending' as const,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tif (record.checksum !== file.checksum) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tname: file.name,\n\t\t\t\t\t\t\tstatus: 'checksum_mismatch' as const,\n\t\t\t\t\t\t\tappliedAt: record.appliedAt,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tname: file.name,\n\t\t\t\t\t\tstatus: 'applied' as const,\n\t\t\t\t\t\tappliedAt: record.appliedAt,\n\t\t\t\t\t};\n\t\t\t\t});\n\n\t\t\t\t// Also show applied migrations that don't have files anymore\n\t\t\t\tfor (const record of applied) {\n\t\t\t\t\tif (!files.some((f) => f.name === record.name)) {\n\t\t\t\t\t\tstatuses.push({\n\t\t\t\t\t\t\tname: record.name,\n\t\t\t\t\t\t\tstatus: 'missing_file' as const,\n\t\t\t\t\t\t\tappliedAt: record.appliedAt,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (options.json) {\n\t\t\t\t\tconsole.log(JSON.stringify(statuses, null, 2));\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log('Migration Status');\n\t\t\t\t\tconsole.log(` Database: ${redactDbUrl(options.db)}`);\n\t\t\t\t\tconsole.log(` Directory: ${options.dir}`);\n\t\t\t\t\tconsole.log('');\n\n\t\t\t\t\tif (statuses.length === 0) {\n\t\t\t\t\t\tconsole.log('No migrations found.');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor (const s of statuses) {\n\t\t\t\t\t\t\tconst icon =\n\t\t\t\t\t\t\t\ts.status === 'applied'\n\t\t\t\t\t\t\t\t\t? 'ā
'\n\t\t\t\t\t\t\t\t\t: s.status === 'pending'\n\t\t\t\t\t\t\t\t\t\t? 'ā³'\n\t\t\t\t\t\t\t\t\t\t: s.status === 'checksum_mismatch'\n\t\t\t\t\t\t\t\t\t\t\t? 'ā ļø'\n\t\t\t\t\t\t\t\t\t\t\t: 'ā';\n\t\t\t\t\t\t\tconst detail =\n\t\t\t\t\t\t\t\t'appliedAt' in s && s.appliedAt\n\t\t\t\t\t\t\t\t\t? ` (applied: ${s.appliedAt.toISOString()})`\n\t\t\t\t\t\t\t\t\t: '';\n\t\t\t\t\t\t\tconsole.log(` ${icon} ${s.name} ā ${s.status}${detail}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst pendingCount = statuses.filter(\n\t\t\t\t\t\t\t(s) => s.status === 'pending',\n\t\t\t\t\t\t).length;\n\t\t\t\t\t\tconst appliedCount = statuses.filter(\n\t\t\t\t\t\t\t(s) => s.status === 'applied',\n\t\t\t\t\t\t).length;\n\n\t\t\t\t\t\tconsole.log('');\n\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t`Total: ${statuses.length} | Applied: ${appliedCount} | Pending: ${pendingCount}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}),\n\t);\n\n// ============================================================================\n// Main Command\n// ============================================================================\n\nexport const migrateCommand = new Command('migrate')\n\t.description('Database migration management')\n\t.addCommand(devCommand)\n\t.addCommand(applyCommand)\n\t.addCommand(rollbackCommand)\n\t.addCommand(statusCommand);\n","/**\n * Migration File ā File I/O, naming conventions, checksums.\n *\n * Handles reading/writing migration SQL files and computing\n * SHA-256 checksums for tamper detection.\n */\n\nimport { createHash } from 'node:crypto';\nimport {\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\twriteFileSync,\n} from 'node:fs';\nimport { join, resolve } from 'node:path';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface MigrationFile {\n\t/** Filename (e.g., \"0001_create_users.sql\") */\n\treadonly name: string;\n\t/** Full path to the file */\n\treadonly path: string;\n\t/** SQL content */\n\treadonly content: string;\n\t/** SHA-256 checksum of content */\n\treadonly checksum: string;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Default directory for migration files */\nexport const DEFAULT_MIGRATIONS_DIR = 'migrations';\n\n/** Migration file naming pattern: NNNN_description.sql */\nconst MIGRATION_FILENAME_PATTERN = /^\\d{4}_[\\w-]+\\.sql$/;\n\n// ============================================================================\n// Checksum\n// ============================================================================\n\n/**\n * Compute SHA-256 checksum of content.\n */\nexport function computeChecksum(content: string): string {\n\treturn createHash('sha256').update(content, 'utf-8').digest('hex');\n}\n\n// ============================================================================\n// File Naming\n// ============================================================================\n\n/**\n * Generate the next migration filename.\n *\n * @param existingFiles - List of existing migration filenames\n * @param description - Human-readable description (e.g., \"create_users\")\n * @returns Filename (e.g., \"0001_create_users.sql\")\n */\nexport function generateMigrationFilename(\n\texistingFiles: readonly string[],\n\tdescription: string,\n): string {\n\tconst maxNum = existingFiles.reduce((max, f) => {\n\t\tconst match = f.match(/^(\\d{4})/);\n\t\treturn match?.[1] ? Math.max(max, Number.parseInt(match[1], 10)) : max;\n\t}, 0);\n\n\tconst nextNum = String(maxNum + 1).padStart(4, '0');\n\tconst sanitized = description\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9_-]/g, '_')\n\t\t.replace(/_+/g, '_')\n\t\t.replace(/^_|_$/g, '');\n\n\treturn `${nextNum}_${sanitized || 'migration'}.sql`;\n}\n\n// ============================================================================\n// File I/O\n// ============================================================================\n\n/**\n * Ensure the migrations directory exists.\n */\nexport function ensureMigrationsDir(dir: string): string {\n\tconst fullPath = resolve(dir);\n\tif (!existsSync(fullPath)) {\n\t\tmkdirSync(fullPath, { recursive: true });\n\t}\n\treturn fullPath;\n}\n\n/**\n * Scan migrations directory and return all valid migration files,\n * sorted by name (lexicographic = chronological with zero-padded numbers).\n */\nexport function scanMigrationFiles(dir: string): readonly MigrationFile[] {\n\tconst fullPath = resolve(dir);\n\tif (!existsSync(fullPath)) {\n\t\treturn [];\n\t}\n\n\tconst entries = readdirSync(fullPath)\n\t\t.filter((f) => MIGRATION_FILENAME_PATTERN.test(f))\n\t\t.sort();\n\n\treturn entries.map((name) => {\n\t\tconst filePath = join(fullPath, name);\n\t\tconst content = readFileSync(filePath, 'utf-8');\n\t\treturn {\n\t\t\tname,\n\t\t\tpath: filePath,\n\t\t\tcontent,\n\t\t\tchecksum: computeChecksum(content),\n\t\t};\n\t});\n}\n\n/**\n * Write a migration file to the migrations directory.\n *\n * @returns The created MigrationFile\n */\nexport function writeMigrationFile(\n\tdir: string,\n\tfilename: string,\n\tcontent: string,\n): MigrationFile {\n\tconst fullDir = ensureMigrationsDir(dir);\n\tconst filePath = join(fullDir, filename);\n\twriteFileSync(filePath, content, 'utf-8');\n\n\treturn {\n\t\tname: filename,\n\t\tpath: filePath,\n\t\tcontent,\n\t\tchecksum: computeChecksum(content),\n\t};\n}\n","/**\n * Push Command ā Schema Provisioning\n *\n * dbsp push - Push schema to database.\n * Additive by default: only creates missing objects.\n * With --drop: recreates from scratch (preserves _dbsp_migrations).\n */\n\nimport type { SchemaChange, SchemaDiff } from '@dbsp/adapter-pgsql';\nimport {\n\tcomparePgsqlDatabaseSchema,\n\tcreatePgsqlAdapter,\n\tgenerateDDL,\n\tgenerateMigrationSQL,\n\tgetNamingPluginForDbCasing,\n} from '@dbsp/adapter-pgsql';\nimport { Command } from 'commander';\nimport { executeDdl } from '../ddl-executor.js';\nimport { createDbConnection, redactDbUrl } from '../utils/db-utils.js';\nimport { loadSchema } from '../utils/schema-loader.js';\n\n/** Table name reserved for migration history ā never dropped by push. */\nconst MIGRATIONS_TABLE = '_dbsp_migrations';\n\nexport const pushCommand = new Command('push')\n\t.description('Push schema to database (additive by default)')\n\t.option(\n\t\t'-s, --schema <path>',\n\t\t'Path to schema file (default: dbsp.schema.ts)',\n\t)\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--schema-name <name>', 'Database schema name (default: public)')\n\t.option('--drop', 'Drop and recreate all objects (preserves migrations)')\n\t.option('--dry-run', 'Print SQL without executing')\n\t.option('--json', 'Output as JSON')\n\t.action(\n\t\tasync (options: {\n\t\t\tschema?: string;\n\t\t\tdb: string;\n\t\t\tschemaName?: string;\n\t\t\tdrop?: boolean;\n\t\t\tdryRun?: boolean;\n\t\t\tjson?: boolean;\n\t\t}) => {\n\t\t\tconst schemaPath = options.schema ?? 'dbsp.schema.ts';\n\t\t\tconst redactedUrl = redactDbUrl(options.db);\n\n\t\t\tif (!options.json) {\n\t\t\t\tconsole.log(\n\t\t\t\t\t`š Pushing schema: ${schemaPath}${options.drop ? ' (with --drop)' : ''}`,\n\t\t\t\t);\n\t\t\t\tconsole.log(` Database: ${redactedUrl}`);\n\t\t\t\tif (options.schemaName) {\n\t\t\t\t\tconsole.log(` Schema: ${options.schemaName}`);\n\t\t\t\t}\n\t\t\t\tif (options.dryRun) {\n\t\t\t\t\tconsole.log(` Mode: DRY RUN (no changes will be applied)`);\n\t\t\t\t}\n\t\t\t\tconsole.log('');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst loaded = await loadSchema(schemaPath);\n\t\t\t\tconst schemaModel = loaded.model;\n\n\t\t\t\tconst { pool } = await createDbConnection(options.db);\n\n\t\t\t\ttry {\n\t\t\t\t\tif (options.drop) {\n\t\t\t\t\t\t// --drop mode: generate full DDL with drops, excluding _dbsp_migrations\n\t\t\t\t\t\tconst statements = generateDDL(schemaModel, {\n\t\t\t\t\t\t\tincludeDropStatements: true,\n\t\t\t\t\t\t\t...(options.schemaName ? { schemaName: options.schemaName } : {}),\n\t\t\t\t\t\t\t...(loaded.dbCasing !== undefined\n\t\t\t\t\t\t\t\t? { naming: getNamingPluginForDbCasing(loaded.dbCasing) }\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst migrationsPattern =\n\t\t\t\t\t\t\tbuildMigrationsTableDropPattern(MIGRATIONS_TABLE);\n\t\t\t\t\t\tconst filtered = statements.filter(\n\t\t\t\t\t\t\t(stmt) => !migrationsPattern.test(stmt),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\toutputResult(filtered, options);\n\n\t\t\t\t\t\tconst result = await executeDdl(pool, filtered, {\n\t\t\t\t\t\t\t...(options.dryRun !== undefined\n\t\t\t\t\t\t\t\t? { dryRun: options.dryRun }\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (options.json) {\n\t\t\t\t\t\t\tconst droppedTables = statements\n\t\t\t\t\t\t\t\t.filter((s) => /DROP\\s+TABLE/i.test(s))\n\t\t\t\t\t\t\t\t.filter((s) => !migrationsPattern.test(s))\n\t\t\t\t\t\t\t\t.map(extractDroppedTableName)\n\t\t\t\t\t\t\t\t.filter((t): t is string => t !== undefined);\n\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tstatus: options.dryRun ? 'dry-run' : 'dropped',\n\t\t\t\t\t\t\t\t\t\ttables: droppedTables,\n\t\t\t\t\t\t\t\t\t\ttablesDropped: droppedTables.length,\n\t\t\t\t\t\t\t\t\t\tstatementsExecuted: result.statementsExecuted,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else if (!options.dryRun) {\n\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\t`\\nā
Push complete: ${result.statementsExecuted} statements executed`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Additive mode: live diff -> generate migration SQL (additive only)\n\t\t\t\t\t\tconst adapter = createPgsqlAdapter(pool);\n\t\t\t\t\t\tconst compareOptions = {\n\t\t\t\t\t\t\t...(options.schemaName ? { schema: options.schemaName } : {}),\n\t\t\t\t\t\t\t...(loaded.dbCasing ? { dbCasing: loaded.dbCasing } : {}),\n\t\t\t\t\t\t\tonWarning: (message: string) => console.warn(`ā ļø ${message}`),\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst diff = await comparePgsqlDatabaseSchema(\n\t\t\t\t\t\t\tadapter,\n\t\t\t\t\t\t\tschemaModel,\n\t\t\t\t\t\t\tcompareOptions,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// Generate SQL for additive changes only (no destructive)\n\t\t\t\t\t\tconst statements = generateMigrationSQL(diff, {\n\t\t\t\t\t\t\tincludeDestructive: false,\n\t\t\t\t\t\t\t...(options.schemaName ? { schemaName: options.schemaName } : {}),\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Collect warnings for skipped non-additive changes\n\t\t\t\t\t\tconst skippedChanges = diff.changes.filter((c) => c.destructive);\n\n\t\t\t\t\t\tif (!options.json && skippedChanges.length > 0) {\n\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\t`ā ļø ${skippedChanges.length} non-additive change(s) skipped:`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tfor (const change of skippedChanges) {\n\t\t\t\t\t\t\t\tconsole.log(` - ${change.details}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconsole.log('');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (statements.length === 0) {\n\t\t\t\t\t\t\tif (options.json) {\n\t\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tstatus: 'up-to-date',\n\t\t\t\t\t\t\t\t\t\t\tstatementsExecuted: 0,\n\t\t\t\t\t\t\t\t\t\t\tskippedChanges: skippedChanges.length,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconsole.log('ā
Database is up to date ā nothing to push.');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// EH-14: return instead of process.exit(0) so pool.end() in finally runs\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\toutputResult(statements, options);\n\n\t\t\t\t\t\tconst result = await executeDdl(pool, statements, {\n\t\t\t\t\t\t\t...(options.dryRun !== undefined\n\t\t\t\t\t\t\t\t? { dryRun: options.dryRun }\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (!options.dryRun) {\n\t\t\t\t\t\t\tconst postApplyDiff = await comparePgsqlDatabaseSchema(\n\t\t\t\t\t\t\t\tadapter,\n\t\t\t\t\t\t\t\tschemaModel,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t...compareOptions,\n\t\t\t\t\t\t\t\t\tpreviouslyAppliedDiff: diff,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tassertNoUnexpectedResidualDrift(postApplyDiff, skippedChanges);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (options.json) {\n\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tstatus: options.dryRun ? 'dry-run' : 'applied',\n\t\t\t\t\t\t\t\t\t\tstatementsExecuted: result.statementsExecuted,\n\t\t\t\t\t\t\t\t\t\tskippedChanges: skippedChanges.length,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else if (!options.dryRun) {\n\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\t`\\nā
Push complete: ${result.statementsExecuted} statement(s) executed`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// EH-14: return so finally runs pool.end() before the outer success path\n\t\t\t\t} finally {\n\t\t\t\t\tawait pool.end();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst message =\n\t\t\t\t\terror instanceof Error ? error.message : 'Unknown error occurred';\n\t\t\t\t// CC-2+EH-7: If --json, error goes to stdout as JSON; otherwise stderr\n\t\t\t\tif (options.json) {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\tJSON.stringify({ status: 'error', error: message }, null, 2),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(`ā Error: ${message}`);\n\t\t\t\t}\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n/**\n * Output SQL statements (dry-run or --json mode).\n */\n/**\n * Match a `DROP TABLE` statement that targets the migrations table, so `--drop`\n * can never destroy dbsp's own migration history.\n *\n * The table name is escaped before it reaches the pattern: an unescaped `.` or\n * `$` in it would otherwise match characters it should not, and a table whose\n * name merely resembles the migrations table would be spared ā or worse, one\n * that should be spared would be dropped.\n *\n * The pattern matches the quoted name anywhere in the statement rather than\n * anchoring to the end. That is safe because `generateDDL` returns one statement\n * per array entry, so a match can never jump across a statement boundary.\n */\nexport function buildMigrationsTableDropPattern(tableName: string): RegExp {\n\tconst escaped = tableName.replace(/[.*+?^${}()|[\\]\\\\]/gu, '\\\\$&');\n\treturn new RegExp(\n\t\t`DROP\\\\s+TABLE(?:\\\\s+IF\\\\s+EXISTS)?(?:\\\\s+\"[^\"]*\"\\\\s*\\\\.)?\\\\s*\"${escaped}\"`,\n\t\t'i',\n\t);\n}\n\n/**\n * Read the table name out of a `DROP TABLE` statement for the JSON report.\n *\n * The name is the last quoted identifier, which skips the schema in\n * `\"public\".\"users\"`, and it may be followed by `CASCADE` before the semicolon.\n * Returns the statement itself when nothing matches, so the report never silently\n * loses a table.\n */\nexport function extractDroppedTableName(statement: string): string {\n\tconst match = statement.match(/\"([^\"]+)\"\\s*(?:CASCADE\\s*)?;?\\s*$/iu);\n\treturn match?.[1] ?? statement;\n}\n\nfunction outputResult(\n\tstatements: readonly string[],\n\toptions: { dryRun?: boolean; json?: boolean },\n): void {\n\tif (options.dryRun && !options.json) {\n\t\tconsole.log(`-- Dry run: ${statements.length} statement(s)\\n`);\n\t\tfor (const stmt of statements) {\n\t\t\tconsole.log(`${stmt};\\n`);\n\t\t}\n\t}\n}\n\nfunction assertNoUnexpectedResidualDrift(\n\tpostApplyDiff: SchemaDiff,\n\tskippedChanges: readonly SchemaChange[],\n): void {\n\tconst skippedKeys = new Set(skippedChanges.map(changeIdentity));\n\tconst unexpected = postApplyDiff.changes.filter(\n\t\t(change) =>\n\t\t\t!(change.destructive && skippedKeys.has(changeIdentity(change))),\n\t);\n\tif (unexpected.length === 0) return;\n\n\tthrow new Error(\n\t\t`Push did not converge after applying DDL; ${unexpected.length} outstanding change(s) remain:\\n` +\n\t\t\tunexpected.map(formatOutstandingChange).join('\\n'),\n\t);\n}\n\nfunction changeIdentity(change: SchemaChange): string {\n\treturn JSON.stringify([\n\t\tchange.kind,\n\t\tchange.table,\n\t\tchange.column ?? null,\n\t\tchange.details,\n\t\tchange.destructive,\n\t]);\n}\n\nfunction formatOutstandingChange(change: SchemaChange): string {\n\tconst target = change.column\n\t\t? `${change.table}.${change.column}`\n\t\t: change.table || 'schema';\n\treturn ` - ${change.details} (${change.kind}: ${target})`;\n}\n","/**\n * DDL Executor ā Transaction-wrapped DDL execution.\n *\n * Shared by `dbsp push` and `dbsp migrate apply`.\n * Executes an array of SQL statements inside a single transaction.\n */\n\nimport type { Pool, PoolClient } from 'pg';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DdlExecutionResult {\n\t/** Number of statements executed */\n\tstatementsExecuted: number;\n\t/** Whether execution was a dry-run (no actual changes) */\n\tdryRun: boolean;\n}\n\n// ============================================================================\n// Executor\n// ============================================================================\n\n/**\n * Execute DDL statements in a transaction.\n *\n * @param pool - pg Pool instance\n * @param statements - SQL statements to execute\n * @param options - Execution options\n * @returns Execution result\n */\nexport async function executeDdl(\n\tpool: Pool,\n\tstatements: readonly string[],\n\toptions?: { dryRun?: boolean },\n): Promise<DdlExecutionResult> {\n\tif (statements.length === 0) {\n\t\treturn { statementsExecuted: 0, dryRun: options?.dryRun ?? false };\n\t}\n\n\tif (options?.dryRun) {\n\t\treturn { statementsExecuted: statements.length, dryRun: true };\n\t}\n\n\tlet client: PoolClient | undefined;\n\ttry {\n\t\tclient = await pool.connect();\n\t\tawait client.query('BEGIN');\n\n\t\tfor (const stmt of statements) {\n\t\t\tawait client.query(stmt);\n\t\t}\n\n\t\tawait client.query('COMMIT');\n\t\treturn { statementsExecuted: statements.length, dryRun: false };\n\t} catch (error) {\n\t\tif (client) {\n\t\t\tawait client.query('ROLLBACK');\n\t\t}\n\t\tthrow error;\n\t} finally {\n\t\tif (client) {\n\t\t\tclient.release();\n\t\t}\n\t}\n}\n","/**\n * DX-030 Block 1: REPL Command\n *\n * dbsp repl [--schema <path>] - Launch interactive REPL.\n * CLI-022: Batch mode support with --eval and --input options.\n */\n\nimport { readFileSync } from 'node:fs';\nimport type { DbCasing } from '@dbsp/types';\nimport { Command } from 'commander';\nimport { config } from '../config.js';\nimport { validateIdentifier } from '../utils/identifier-validation.js';\nimport { loadSchema, loadSchemaFromCwd } from '../utils/schema-loader.js';\n\nexport interface ReplOptions {\n\tschema?: string;\n\t/** CLI-020: Database connection URL for execution mode */\n\tdb?: string;\n\t/** CLI-022: Single query to evaluate (batch mode) */\n\teval?: string;\n\t/** CLI-022: File containing queries to execute (batch mode, one per line) */\n\tinput?: string;\n\t/** CLI-022: Output format for batch mode */\n\tformat?: 'text' | 'json';\n\t/** DEMO-E2E: Assertion file for validating query output */\n\tassert?: string;\n\t/** CLI-IMPORT: SQL files to import before queries (injected as .import commands) */\n\timport?: string[];\n\t/** CLI-USE: PostgreSQL schema to use (injected as .use command) */\n\tuse?: string;\n\t/** CLI-MUT: Start REPL with parse mode enabled */\n\tparse?: boolean;\n\t/** CLI-MUT: Start REPL with exec mode enabled */\n\texec?: boolean;\n\t/** CLI-CONFIG: Custom config file path (default: ~/.dbsp/config.json) */\n\tconfig?: string;\n\t/** CLI-CASING: Column naming convention (describes DB column casing) */\n\tcasing?: 'snake' | 'camel' | 'none';\n}\n\nexport const replCommand = new Command('repl')\n\t.description('Launch interactive REPL for exploring schema and queries')\n\t.option('-s, --schema <path>', 'Path to schema file (default: auto-detect)')\n\t.option(\n\t\t'-d, --db <url>',\n\t\t'PostgreSQL connection URL for execution mode (e.g., postgres://localhost/mydb)',\n\t)\n\t.option('-e, --eval <query>', 'Execute a single query and exit (batch mode)')\n\t.option(\n\t\t'-i, --input <file>',\n\t\t'Execute queries from file, one per line (batch mode)',\n\t)\n\t.option(\n\t\t'-f, --format <format>',\n\t\t'Output format for batch mode: text (default) or json',\n\t\t'text',\n\t)\n\t.option(\n\t\t'-a, --assert <file>',\n\t\t'Assertion file to validate query output (requires --input)',\n\t)\n\t.option(\n\t\t'--import <files...>',\n\t\t'SQL files to import before queries (equivalent to .import commands)',\n\t)\n\t.option(\n\t\t'--use <schema>',\n\t\t'PostgreSQL schema to use (equivalent to .use command)',\n\t)\n\t.option('--parse', 'Start REPL with parse mode enabled (.parse toggle)')\n\t.option('--exec', 'Start REPL with exec mode enabled (.exec toggle)')\n\t.option(\n\t\t'--casing <type>',\n\t\t'Column naming convention: snake (DB uses snake_case), camel (DB uses camelCase), none (preserve as-is)',\n\t)\n\t.option(\n\t\t'-c, --config <path>',\n\t\t'Custom config file path (default: ~/.dbsp/config.json)',\n\t)\n\t.action(async (options: ReplOptions) => {\n\t\t// Set custom config path if provided\n\t\tif (options.config) {\n\t\t\tconfig.setConfigPath(options.config);\n\t\t}\n\t\t// Load config\n\t\tconfig.load();\n\t\ttry {\n\t\t\t// Load schema\n\t\t\tlet schemaPath: string;\n\t\t\tlet schema: Awaited<ReturnType<typeof loadSchema>>;\n\n\t\t\tif (options.schema) {\n\t\t\t\tschema = await loadSchema(options.schema);\n\t\t\t\tschemaPath = options.schema;\n\t\t\t} else {\n\t\t\t\tconst result = await loadSchemaFromCwd();\n\t\t\t\tschema = result.schema;\n\t\t\t\tschemaPath = result.path;\n\t\t\t}\n\n\t\t\t// DEMO-E2E: Validate --assert requires --input\n\t\t\tif (options.assert && !options.input) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'--assert requires --input (assertion files validate query output from input files)',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// CLI-IMPORT: Validate that --import requires batch mode (SQL file execution)\n\t\t\t// Note: --use, --parse, --exec work in interactive mode (REPL state setup)\n\t\t\tif (options.import && !options.eval && !options.input) {\n\t\t\t\tthrow new Error('--import requires batch mode (--eval or --input)');\n\t\t\t}\n\n\t\t\t// SEC: Validate --use schema name at the entry point so both the batch path\n\t\t\t// (which injects `.use <schema>`) and the interactive path (which passes\n\t\t\t// initialSchemaName) are protected against SQL injection.\n\t\t\tif (options.use) {\n\t\t\t\tvalidateIdentifier(options.use, 'schema');\n\t\t\t}\n\n\t\t\t// CLI-CASING: explicit flag wins; otherwise use the schema declaration.\n\t\t\tconst dbCasing = mapReplCasingOption(options.casing) ?? schema.dbCasing;\n\n\t\t\t// CLI-022: Batch mode - execute queries without interactive UI\n\t\t\tif (options.eval || options.input) {\n\t\t\t\tconst { runBatchMode } = await import('../repl/batch.js');\n\t\t\t\tconst queries: string[] = [];\n\n\t\t\t\t// CLI-USE: Inject .use command first (schema scoping)\n\t\t\t\tif (options.use) {\n\t\t\t\t\tqueries.push(`.use ${options.use}`);\n\t\t\t\t}\n\n\t\t\t\t// CLI-IMPORT: Inject .import commands for SQL files\n\t\t\t\tif (options.import) {\n\t\t\t\t\tfor (const file of options.import) {\n\t\t\t\t\t\tqueries.push(`.import ${file}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (options.eval) {\n\t\t\t\t\tqueries.push(options.eval);\n\t\t\t\t}\n\n\t\t\t\tif (options.input) {\n\t\t\t\t\t// EH-2: Map ENOENT to a friendly error instead of raw stack trace\n\t\t\t\t\tlet content: string;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcontent = readFileSync(options.input, 'utf-8');\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconst isNotFound =\n\t\t\t\t\t\t\terr instanceof Error &&\n\t\t\t\t\t\t\t'code' in err &&\n\t\t\t\t\t\t\t(err as NodeJS.ErrnoException).code === 'ENOENT';\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\tisNotFound\n\t\t\t\t\t\t\t\t? `Input file not found: ${options.input}`\n\t\t\t\t\t\t\t\t: `Failed to read input file: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tqueries.push(...content.split('\\n'));\n\t\t\t\t}\n\n\t\t\t\tawait runBatchMode({\n\t\t\t\t\tqueries,\n\t\t\t\t\tschema,\n\t\t\t\t\tschemaPath,\n\t\t\t\t\tformat: options.format ?? 'text',\n\t\t\t\t\t...(options.db && { databaseUrl: options.db }),\n\t\t\t\t\t...(options.assert && { assertFile: options.assert }),\n\t\t\t\t\t...(dbCasing && { dbCasing }),\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Dynamic import to avoid loading React/Ink for other commands\n\t\t\tconst { startRepl } = await import('../repl/index.js');\n\t\t\t// CLI-020: Pass database URL if provided\n\t\t\t// CLI-MUT: Pass initial REPL state options\n\t\t\tawait startRepl({\n\t\t\t\tschema,\n\t\t\t\tschemaPath,\n\t\t\t\t...(options.db && { databaseUrl: options.db }),\n\t\t\t\t...(options.use && { initialSchemaName: options.use }),\n\t\t\t\t...(options.parse && { initialParseMode: true }),\n\t\t\t\t...(options.exec && { initialExecMode: true }),\n\t\t\t\t...(dbCasing && { dbCasing }),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconsole.error(`ā ${message}`);\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nfunction mapReplCasingOption(\n\tcasing: ReplOptions['casing'],\n): DbCasing | undefined {\n\tswitch (casing) {\n\t\tcase 'snake':\n\t\t\treturn 'snake_case';\n\t\tcase 'camel':\n\t\t\treturn 'camelCase';\n\t\tcase 'none':\n\t\t\treturn 'preserve';\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n","/**\n * Verify Command ā Schema Drift Detection\n *\n * dbsp verify - Compare schema vs real database using the comparison engine.\n * Detects drift in tables, columns, types, nullable, defaults, FKs, indexes.\n */\n\nimport {\n\tcomparePgsqlDatabaseSchema,\n\tcreatePgsqlAdapter,\n} from '@dbsp/adapter-pgsql';\nimport { Command } from 'commander';\nimport { createDbConnection, redactDbUrl } from '../utils/db-utils.js';\nimport { loadSchema } from '../utils/schema-loader.js';\nimport { formatVerifyResult, verifyFromDiff } from '../verifier.js';\n\nexport const verifyCommand = new Command('verify')\n\t.description('Compare schema vs real database (drift detection)')\n\t.option(\n\t\t'-s, --schema <path>',\n\t\t'Path to schema file (default: dbsp.schema.ts)',\n\t)\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--schema-name <name>', 'Database schema name (default: public)')\n\t.option('--json', 'Output as JSON')\n\t.action(\n\t\tasync (options: {\n\t\t\tschema?: string;\n\t\t\tdb: string;\n\t\t\tschemaName?: string;\n\t\t\tjson?: boolean;\n\t\t}) => {\n\t\t\tconst schemaPath = options.schema ?? 'dbsp.schema.ts';\n\n\t\t\tconst redactedUrl = redactDbUrl(options.db);\n\n\t\t\tif (!options.json) {\n\t\t\t\tconsole.log(`š Verifying schema: ${schemaPath}`);\n\t\t\t\tconsole.log(` Database: ${redactedUrl}`);\n\t\t\t\tif (options.schemaName) {\n\t\t\t\t\tconsole.log(` Schema: ${options.schemaName}`);\n\t\t\t\t}\n\t\t\t\tconsole.log('');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// Load schema from file ā ModelIR\n\t\t\t\tconst loaded = await loadSchema(schemaPath);\n\t\t\t\tconst schemaModel = loaded.model;\n\n\t\t\t\t// Connect to database\n\t\t\t\tconst { pool } = await createDbConnection(options.db);\n\n\t\t\t\ttry {\n\t\t\t\t\tconst adapter = createPgsqlAdapter(pool);\n\t\t\t\t\t// Live diff: introspect database and canonicalise PostgreSQL CHECK\n\t\t\t\t\t// expressions before comparing.\n\t\t\t\t\tconst diff = await comparePgsqlDatabaseSchema(adapter, schemaModel, {\n\t\t\t\t\t\t...(options.schemaName ? { schema: options.schemaName } : {}),\n\t\t\t\t\t\t...(loaded.dbCasing !== undefined\n\t\t\t\t\t\t\t? { dbCasing: loaded.dbCasing }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\tonWarning: (message) => console.warn(`ā ļø ${message}`),\n\t\t\t\t\t});\n\n\t\t\t\t\t// Convert to verify result\n\t\t\t\t\t// Keep the legacy reporting fields sourced from introspection so\n\t\t\t\t\t// --json consumers continue to see database table names as before.\n\t\t\t\t\tconst dbModel = await adapter.introspect({\n\t\t\t\t\t\t...(options.schemaName ? { schema: options.schemaName } : {}),\n\t\t\t\t\t});\n\t\t\t\t\tconst schemaTables = Array.from(schemaModel.tables.keys());\n\t\t\t\t\tconst dbTables = Array.from(dbModel.tables.keys());\n\t\t\t\t\tconst result = verifyFromDiff(diff, schemaTables, dbTables);\n\n\t\t\t\t\t// Output\n\t\t\t\t\tif (options.json) {\n\t\t\t\t\t\t// Exclude the full diff meta from JSON output (too verbose)\n\t\t\t\t\t\tconst { diff: _diff, ...jsonResult } = result;\n\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t...jsonResult,\n\t\t\t\t\t\t\t\t\tsummary: diff.summary,\n\t\t\t\t\t\t\t\t\thasDestructive: diff.hasDestructive,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconsole.log(formatVerifyResult(result));\n\t\t\t\t\t}\n\n\t\t\t\t\t// EH-14: set exit code; let finally run pool.end() before process exits\n\t\t\t\t\tprocess.exitCode = result.valid ? 0 : 1;\n\t\t\t\t\treturn;\n\t\t\t\t} finally {\n\t\t\t\t\t// Close database connection\n\t\t\t\t\tawait pool.end();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst message =\n\t\t\t\t\terror instanceof Error ? error.message : 'Unknown error occurred';\n\t\t\t\t// CC-2+EH-7: If --json, error goes to stdout as JSON; otherwise stderr\n\t\t\t\tif (options.json) {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\tJSON.stringify({ status: 'error', error: message }, null, 2),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(`ā Error: ${message}`);\n\t\t\t\t}\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n","/**\n * Schema Verifier ā Drift Detection via Comparison Engine\n *\n * Compares schema definition against real database using the\n * adapter's compareSchemata engine for full drift detection.\n *\n * Detects: tables, columns, types, nullable, defaults, FKs, indexes, PKs.\n */\n\nimport type { ChangeKind, SchemaChange, SchemaDiff } from '@dbsp/adapter-pgsql';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type DriftSeverity = 'error' | 'warning' | 'info';\n\nexport type DriftType =\n\t// Tables\n\t| 'missing_table_in_db'\n\t| 'missing_table_in_schema'\n\t// Columns\n\t| 'missing_column_in_db'\n\t| 'missing_column_in_schema'\n\t| 'type_mismatch'\n\t| 'nullable_mismatch'\n\t| 'default_mismatch'\n\t| 'unique_mismatch'\n\t// Constraints\n\t| 'primary_key_mismatch'\n\t| 'missing_fk_in_db'\n\t| 'missing_fk_in_schema'\n\t| 'fk_on_delete_mismatch'\n\t// Indexes\n\t| 'missing_index_in_db'\n\t| 'missing_index_in_schema'\n\t// CHECK constraints\n\t| 'missing_check_in_db'\n\t| 'missing_check_in_schema'\n\t// ENUM types\n\t| 'missing_enum_in_db'\n\t| 'missing_enum_in_schema'\n\t| 'enum_value_mismatch'\n\t// Column enhancements\n\t| 'collation_mismatch'\n\t| 'identity_mismatch'\n\t// Comments\n\t| 'comment_mismatch'\n\t// Extensions & Sequences\n\t| 'missing_extension'\n\t| 'missing_sequence'\n\t| 'sequence_mismatch'\n\t// Constraints\n\t| 'constraint_validation_mismatch'\n\t// Row-Level Security\n\t| 'rls_enabled_mismatch'\n\t| 'missing_policy_in_db'\n\t| 'missing_policy_in_schema';\n\nexport interface DriftIssue {\n\t/** Issue severity */\n\tseverity: DriftSeverity;\n\t/** Human-readable message */\n\tmessage: string;\n\t/** Table affected (if any) */\n\ttable?: string;\n\t/** Column affected (if any) */\n\tcolumn?: string;\n\t/** Issue type for programmatic handling */\n\ttype: DriftType;\n}\n\nexport interface VerifyResult {\n\t/** Whether the schema matches the database */\n\tvalid: boolean;\n\t/** List of drift issues found */\n\tissues: DriftIssue[];\n\t/** Tables in schema */\n\tschemaTables: string[];\n\t/** Tables in database */\n\tdbTables: string[];\n\t/** Structured diff (for programmatic consumers) */\n\tdiff: SchemaDiff;\n}\n\n// ============================================================================\n// Change ā Drift Mapping\n// ============================================================================\n\nconst CHANGE_TO_DRIFT: Record<\n\tChangeKind,\n\t{ type: DriftType; severity: DriftSeverity }\n> = {\n\tcreate_table: { type: 'missing_table_in_db', severity: 'error' },\n\tdrop_table: { type: 'missing_table_in_schema', severity: 'warning' },\n\tadd_column: { type: 'missing_column_in_db', severity: 'error' },\n\tdrop_column: { type: 'missing_column_in_schema', severity: 'info' },\n\talter_column_type: { type: 'type_mismatch', severity: 'error' },\n\talter_column_nullable: { type: 'nullable_mismatch', severity: 'warning' },\n\talter_column_default: { type: 'default_mismatch', severity: 'warning' },\n\talter_column_unique: { type: 'unique_mismatch', severity: 'warning' },\n\tadd_primary_key: { type: 'primary_key_mismatch', severity: 'error' },\n\tdrop_primary_key: { type: 'primary_key_mismatch', severity: 'error' },\n\tadd_foreign_key: { type: 'missing_fk_in_db', severity: 'error' },\n\tdrop_foreign_key: { type: 'missing_fk_in_schema', severity: 'warning' },\n\talter_foreign_key: { type: 'fk_on_delete_mismatch', severity: 'warning' },\n\tcreate_index: { type: 'missing_index_in_db', severity: 'warning' },\n\tdrop_index: { type: 'missing_index_in_schema', severity: 'info' },\n\t// CHECK constraints\n\tadd_check_constraint: { type: 'missing_check_in_db', severity: 'warning' },\n\tdrop_check_constraint: { type: 'missing_check_in_schema', severity: 'info' },\n\t// ENUM types\n\tcreate_enum: { type: 'missing_enum_in_db', severity: 'error' },\n\talter_enum_add_value: { type: 'enum_value_mismatch', severity: 'warning' },\n\tdrop_enum: { type: 'missing_enum_in_schema', severity: 'warning' },\n\t// Column enhancements\n\talter_column_collation: { type: 'collation_mismatch', severity: 'warning' },\n\talter_column_identity: { type: 'identity_mismatch', severity: 'warning' },\n\t// Comments\n\tadd_comment: { type: 'comment_mismatch', severity: 'info' },\n\tdrop_comment: { type: 'comment_mismatch', severity: 'info' },\n\t// Extensions & Sequences\n\tcreate_extension: { type: 'missing_extension', severity: 'error' },\n\tdrop_extension: { type: 'missing_extension', severity: 'info' },\n\tcreate_sequence: { type: 'missing_sequence', severity: 'warning' },\n\talter_sequence: { type: 'sequence_mismatch', severity: 'warning' },\n\tdrop_sequence: { type: 'missing_sequence', severity: 'info' },\n\t// Constraints\n\tvalidate_constraint: {\n\t\ttype: 'constraint_validation_mismatch',\n\t\tseverity: 'warning',\n\t},\n\t// Row-Level Security\n\tenable_rls: { type: 'rls_enabled_mismatch', severity: 'warning' },\n\tdisable_rls: { type: 'rls_enabled_mismatch', severity: 'warning' },\n\tcreate_policy: { type: 'missing_policy_in_db', severity: 'warning' },\n\tdrop_policy: { type: 'missing_policy_in_schema', severity: 'warning' },\n};\n\nfunction changeToDriftIssue(change: SchemaChange): DriftIssue {\n\tconst mapping = CHANGE_TO_DRIFT[change.kind] ?? {\n\t\ttype: 'type_mismatch' as DriftType,\n\t\tseverity: 'warning' as DriftSeverity,\n\t};\n\treturn {\n\t\tseverity: mapping.severity,\n\t\ttype: mapping.type,\n\t\ttable: change.table,\n\t\t...(change.column !== undefined ? { column: change.column } : {}),\n\t\tmessage: change.details,\n\t};\n}\n\n// ============================================================================\n// Verification (from SchemaDiff)\n// ============================================================================\n\n/**\n * Convert a SchemaDiff into a VerifyResult.\n *\n * @param diff - Structured diff from compareSchemata()\n * @param schemaTables - Table names in schema (for backward compat)\n * @param dbTables - Table names in database (for backward compat)\n */\nexport function verifyFromDiff(\n\tdiff: SchemaDiff,\n\tschemaTables: string[],\n\tdbTables: string[],\n): VerifyResult {\n\tconst issues = diff.changes.map(changeToDriftIssue);\n\n\t// Sort by severity (error > warning > info)\n\tconst severityOrder: Record<DriftSeverity, number> = {\n\t\terror: 0,\n\t\twarning: 1,\n\t\tinfo: 2,\n\t};\n\tissues.sort(\n\t\t(a: DriftIssue, b: DriftIssue) =>\n\t\t\tseverityOrder[a.severity] - severityOrder[b.severity],\n\t);\n\n\tconst hasErrors = issues.some((i: DriftIssue) => i.severity === 'error');\n\n\treturn {\n\t\tvalid: !hasErrors,\n\t\tissues,\n\t\tschemaTables,\n\t\tdbTables,\n\t\tdiff,\n\t};\n}\n\n// ============================================================================\n// Format\n// ============================================================================\n\n/**\n * Format verification result for CLI output.\n */\nexport function formatVerifyResult(result: VerifyResult): string {\n\tconst lines: string[] = [];\n\n\tif (result.valid) {\n\t\tlines.push('ā
Schema matches database');\n\t} else {\n\t\tlines.push('ā Schema drift detected');\n\t}\n\n\tlines.push('');\n\tlines.push(`Tables in schema: ${result.schemaTables.length}`);\n\tlines.push(`Tables in database: ${result.dbTables.length}`);\n\tlines.push('');\n\n\tif (result.issues.length === 0) {\n\t\tlines.push('No issues found.');\n\t} else {\n\t\tconst errors = result.issues.filter((i) => i.severity === 'error');\n\t\tconst warnings = result.issues.filter((i) => i.severity === 'warning');\n\t\tconst infos = result.issues.filter((i) => i.severity === 'info');\n\n\t\tif (errors.length > 0) {\n\t\t\tlines.push(`ā ${errors.length} error(s):`);\n\t\t\tfor (const issue of errors) {\n\t\t\t\tlines.push(` ${issue.message}`);\n\t\t\t}\n\t\t\tlines.push('');\n\t\t}\n\n\t\tif (warnings.length > 0) {\n\t\t\tlines.push(`ā ļø ${warnings.length} warning(s):`);\n\t\t\tfor (const issue of warnings) {\n\t\t\t\tlines.push(` ${issue.message}`);\n\t\t\t}\n\t\t\tlines.push('');\n\t\t}\n\n\t\tif (infos.length > 0) {\n\t\t\tlines.push(`ā¹ļø ${infos.length} info:`);\n\t\t\tfor (const issue of infos) {\n\t\t\t\tlines.push(` ${issue.message}`);\n\t\t\t}\n\t\t\tlines.push('');\n\t\t}\n\t}\n\n\treturn lines.join('\\n');\n}\n"],"mappings":"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","names":["Command","outputPath","mkdirSync","writeFileSync","dirname","resolve","Command","Command","resolve","mkdirSync","dirname","writeFileSync","Command","mkdirSync","writeFileSync","resolve","Command","comparePgsqlDatabaseSchema","createPgsqlAdapter","generateMigrationSQL","Command","Command","createPgsqlAdapter","comparePgsqlDatabaseSchema","generateMigrationSQL","readFileSync","Command","Command","readFileSync","comparePgsqlDatabaseSchema","createPgsqlAdapter","Command","Command","createPgsqlAdapter","comparePgsqlDatabaseSchema","Command"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/generate.ts","../src/commands/introspect.ts","../src/commands/migrate.ts","../src/migration-file.ts","../src/commands/plan.ts","../src/commands/push.ts","../src/ddl-executor.ts","../src/commands/repl.ts","../src/commands/verify.ts","../src/verifier.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * ARCH-002 Block 3: CLI Scaffold\n *\n * dbsp CLI - Schema-first code generation for db-semantic-planner.\n */\n\nimport { Command, CommanderError } from 'commander';\nimport { generateCommand } from './commands/generate.js';\nimport { introspectCommand } from './commands/introspect.js';\nimport { migrateCommand } from './commands/migrate.js';\nimport { planCommand } from './commands/plan.js';\nimport { pushCommand } from './commands/push.js';\nimport { replCommand } from './commands/repl.js';\nimport { verifyCommand } from './commands/verify.js';\n\nconst program = new Command();\n\nfunction selectedCommand(\n\targv: readonly string[],\n\tcommands: readonly Command[],\n): { readonly command: Command; readonly index: number } | undefined {\n\tfor (let index = 0; index < argv.length; index += 1) {\n\t\tconst argument = argv[index];\n\t\tif (argument === '--') return undefined;\n\t\tif (argument?.startsWith('-')) continue;\n\t\tconst command = commands.find((candidate) => candidate.name() === argument);\n\t\treturn command === undefined ? undefined : { command, index };\n\t}\n\treturn undefined;\n}\n\nfunction requestsPlanJson(\n\targv: readonly string[],\n\tcommands: readonly Command[],\n): boolean {\n\tconst selected = selectedCommand(argv, commands);\n\tif (selected?.command !== planCommand) return false;\n\n\tfor (let index = selected.index + 1; index < argv.length; index += 1) {\n\t\tconst argument = argv[index];\n\t\tif (argument === '--') break;\n\t\tif (\n\t\t\t(argument === '--format' && argv[index + 1] === 'json') ||\n\t\t\targument === '--format=json'\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nprogram\n\t.name('dbsp')\n\t.description('Schema-first code generation for db-semantic-planner')\n\t.version('0.0.1');\n\n// Register commands\nprogram.addCommand(generateCommand);\nprogram.addCommand(introspectCommand);\nprogram.addCommand(migrateCommand);\nprogram.addCommand(planCommand);\nprogram.addCommand(pushCommand);\nprogram.addCommand(replCommand);\nprogram.addCommand(verifyCommand);\n\nconst planJsonRequested = requestsPlanJson(\n\tprocess.argv.slice(2),\n\tprogram.commands,\n);\n\n// Commander validates root options before transferring control to a subcommand.\n// For a resolved `plan --format json` invocation, avoid emitting its eager\n// plaintext diagnostic alongside the JSON error document produced below.\nif (planJsonRequested) {\n\tprogram.configureOutput({ writeErr: () => {} });\n}\n\n// CC-15: Intercept Commander parse errors so --json commands receive a JSON\n// error object on stdout instead of a plain-text usage message.\nprogram.exitOverride();\n\ntry {\n\tprogram.parse();\n} catch (err) {\n\t// Commander throws CommanderError for --help, --version, and parse errors.\n\t// Exit 0 for informational outputs (help/version); only exit 1 for real errors.\n\tif (err instanceof CommanderError && err.exitCode === 0) {\n\t\tprocess.exit(0);\n\t}\n\tconst message = err instanceof Error ? err.message : 'Command parse error';\n\tif (process.argv.includes('--json') || planJsonRequested) {\n\t\tconsole.log(JSON.stringify({ status: 'error', error: message }, null, 2));\n\t} else {\n\t\tconsole.error(`ā ${message}`);\n\t}\n\tprocess.exit(1);\n}\n","/**\n * ARCH-002 Block 3+4+5: Generate Command\n * CLI-DDL: Added DDL generation target\n * ARCH-005: Migrated to schema() API, removed legacy generators\n *\n * dbsp generate <target> - Generate code from schema.\n *\n * Targets:\n * - ddl: Generate SQL DDL (CREATE TABLE statements)\n *\n * Deprecated targets (removed in ARCH-005):\n * - manifest: Removed legacy manifest generator\n * - kysely: Removed legacy Kysely generator\n */\n\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport type { DbCasing } from '@dbsp/types';\nimport { Command } from 'commander';\nimport { loadSchema, loadSchemaFromCwd } from '../utils/schema-loader.js';\n\nexport type GenerateCasingOption = 'snake' | 'camel' | 'none';\n\nexport const generateCommand = new Command('generate')\n\t.description('Generate code from schema')\n\t.argument('<target>', 'Target to generate: ddl')\n\t.option('-s, --schema <path>', 'Path to schema file (default: auto-detect)')\n\t.option('-o, --out <dir>', 'Output directory (default: ./generated/<target>)')\n\t.option('--output <dir>', 'Output directory (alias for --out)')\n\t.option('--drop', 'Include DROP TABLE IF EXISTS statements (ddl only)')\n\t.option('--schema-name <name>', 'Database schema name (ddl only)')\n\t.option(\n\t\t'--dialect <name>',\n\t\t'Database dialect: postgresql | mysql | sqlite | mssql (default: postgresql)',\n\t)\n\t.option(\n\t\t'--casing <type>',\n\t\t'Column naming: snake | camel | none (default: based on dialect)',\n\t)\n\t.action(\n\t\tasync (\n\t\t\ttarget: string,\n\t\t\toptions: {\n\t\t\t\tschema?: string;\n\t\t\t\tout?: string;\n\t\t\t\toutput?: string;\n\t\t\t\tdrop?: boolean;\n\t\t\t\tschemaName?: string;\n\t\t\t\tdialect?: string;\n\t\t\t\tcasing?: GenerateCasingOption;\n\t\t\t},\n\t\t) => {\n\t\t\ttry {\n\t\t\t\t// Reject the target BEFORE loading the schema: loading it executes the\n\t\t\t\t// user's schema module, and there is no reason to run their code for a\n\t\t\t\t// target we are going to refuse anyway.\n\t\t\t\tif (target === 'manifest' || target === 'kysely') {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Target '${target}' has been removed. ` +\n\t\t\t\t\t\t\t`Use 'ddl' for SQL generation, or the 'introspect' command to generate a schema file.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (target !== 'ddl') {\n\t\t\t\t\tthrow new Error(`Unknown target: ${target}. Available targets: ddl`);\n\t\t\t\t}\n\n\t\t\t\t// Load schema (ARCH-005: only schema() format supported)\n\t\t\t\tlet schema: Awaited<ReturnType<typeof loadSchema>>;\n\t\t\t\tlet schemaPath: string;\n\n\t\t\t\tif (options.schema) {\n\t\t\t\t\tschema = await loadSchema(options.schema);\n\t\t\t\t\tschemaPath = options.schema;\n\t\t\t\t} else {\n\t\t\t\t\tconst result = await loadSchemaFromCwd();\n\t\t\t\t\tschema = result.schema;\n\t\t\t\t\tschemaPath = result.path;\n\t\t\t\t}\n\n\t\t\t\t// For DDL without --output, we output to stdout so use stderr for info\n\t\t\t\tconst outputPath = options.out ?? options.output;\n\t\t\t\tconst useStdout = target === 'ddl' && !outputPath;\n\t\t\t\tconst log = useStdout ? console.error : console.log;\n\n\t\t\t\tlog(`š Loaded schema from: ${schemaPath}`);\n\n\t\t\t\t// Validate dialect option\n\t\t\t\tconst dialect = options.dialect ?? 'postgresql';\n\t\t\t\tif (!isDialectSupported(dialect)) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`ā ļø Warning: Only 'postgresql' dialect is currently supported. Using postgresql.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Generate based on target\n\t\t\t\tswitch (target) {\n\t\t\t\t\tcase 'ddl': {\n\t\t\t\t\t\t// Determine casing: explicit option > schema export > dialect default.\n\t\t\t\t\t\tconst dbCasing =\n\t\t\t\t\t\t\tmapCasingToDbCasing(options.casing) ??\n\t\t\t\t\t\t\tschema.dbCasing ??\n\t\t\t\t\t\t\t('snake_case' as const);\n\t\t\t\t\t\tconst casingLabel = formatGenerateCasingLabel(dbCasing);\n\n\t\t\t\t\t\t// Import adapter from adapter-pgsql (compile-only, no DB connection needed)\n\t\t\t\t\t\tconst { createPgsqlCompileOnlyAdapter } = await import(\n\t\t\t\t\t\t\t'@dbsp/adapter-pgsql'\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst adapter = createPgsqlCompileOnlyAdapter({\n\t\t\t\t\t\t\tdbCasing,\n\t\t\t\t\t\t\t...(options.schemaName ? { schemaName: options.schemaName } : {}),\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// ARCH-005: Use schema.model directly (already ModelIR)\n\t\t\t\t\t\t\tconst ddlStatements = adapter.generateDDL(schema.model, {\n\t\t\t\t\t\t\t\t...(options.drop !== undefined && {\n\t\t\t\t\t\t\t\t\tincludeDropStatements: options.drop,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tconst ddlContent = ddlStatements.join('\\n\\n');\n\t\t\t\t\t\t\tconst outputPath = options.out ?? options.output;\n\n\t\t\t\t\t\t\tif (outputPath) {\n\t\t\t\t\t\t\t\t// Write to file if --output is specified\n\t\t\t\t\t\t\t\tconst outPath = outputPath.endsWith('.sql')\n\t\t\t\t\t\t\t\t\t? resolve(process.cwd(), outputPath)\n\t\t\t\t\t\t\t\t\t: resolve(process.cwd(), outputPath, 'schema.sql');\n\n\t\t\t\t\t\t\t\tmkdirSync(dirname(outPath), { recursive: true });\n\t\t\t\t\t\t\t\twriteFileSync(outPath, ddlContent, 'utf-8');\n\n\t\t\t\t\t\t\t\tconsole.log(`ā
Generated DDL: ${outPath}`);\n\t\t\t\t\t\t\t\tconsole.log(` Tables: ${schema.tableNames.length}`);\n\t\t\t\t\t\t\t\tconsole.log(` Statements: ${ddlStatements.length}`);\n\t\t\t\t\t\t\t\tconsole.log(` Casing: ${casingLabel}`);\n\t\t\t\t\t\t\t\tif (options.drop) {\n\t\t\t\t\t\t\t\t\tconsole.log(` Includes DROP statements`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (options.schemaName) {\n\t\t\t\t\t\t\t\t\tconsole.log(` Schema: ${options.schemaName}`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Output DDL to stdout (for piping)\n\t\t\t\t\t\t\t\t// Info messages (schema loaded) went to stderr\n\t\t\t\t\t\t\t\tconsole.log(ddlContent);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tconsole.error(`ā ${message}`);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\nexport function isDialectSupported(dialect: string): dialect is 'postgresql' {\n\treturn dialect === 'postgresql';\n}\n\nexport function mapCasingToDbCasing(\n\tcasing: GenerateCasingOption | undefined,\n): DbCasing | undefined {\n\tswitch (casing) {\n\t\tcase 'snake':\n\t\t\treturn 'snake_case';\n\t\tcase 'camel':\n\t\t\treturn 'camelCase';\n\t\tcase 'none':\n\t\t\treturn 'preserve';\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nfunction formatGenerateCasingLabel(\n\tdbCasing: DbCasing,\n): 'snake' | 'camel' | 'none' {\n\tswitch (dbCasing) {\n\t\tcase 'snake_case':\n\t\t\treturn 'snake';\n\t\tcase 'camelCase':\n\t\t\treturn 'camel';\n\t\tcase 'preserve':\n\t\t\treturn 'none';\n\t}\n}\n","/**\n * CLI-DDL: Introspect Command\n *\n * dbsp introspect - Generate schema.ts from database introspection.\n */\n\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { Command } from 'commander';\nimport {\n\tgenerateSchemaFileWithDiagnostics,\n\ttype SchemaCodegenOptions,\n} from '../generators/schema-codegen.js';\nimport { createDbConnection, redactDbUrl } from '../utils/db-utils.js';\n\nfunction uniqueWarnings(warnings: readonly string[]): string[] {\n\tconst seen = new Set<string>();\n\tconst unique: string[] = [];\n\tfor (const warning of warnings) {\n\t\tif (seen.has(warning)) continue;\n\t\tseen.add(warning);\n\t\tunique.push(warning);\n\t}\n\treturn unique;\n}\n\nfunction reportWarnings(warnings: readonly string[]): void {\n\tfor (const warning of warnings) {\n\t\tconsole.log(` ā ļø ${warning}`);\n\t}\n}\n\nexport const introspectCommand = new Command('introspect')\n\t.description('Generate schema.ts from database introspection')\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('-o, --out <file>', 'Output schema file', './dbsp.schema.ts')\n\t.option('--schema-name <name>', 'Database schema name', 'public')\n\t.option(\n\t\t'--exclude <patterns>',\n\t\t'Tables to exclude (comma-separated glob patterns)',\n\t\t'_migrations,_prisma*,pg_*',\n\t)\n\t.option('--include <patterns>', 'Tables to include (comma-separated)')\n\t.option('--no-db-type-comments', 'Omit original DB type comments')\n\t.option(\n\t\t'--db-casing <casing>',\n\t\t'Database column casing (snake_case ā camelCase in generated code)',\n\t\t'snake_case',\n\t)\n\t.action(\n\t\tasync (options: {\n\t\t\tdb: string;\n\t\t\tout: string;\n\t\t\tschemaName: string;\n\t\t\texclude: string;\n\t\t\tinclude?: string;\n\t\t\tdbTypeComments: boolean;\n\t\t\tdbCasing: 'snake_case' | 'camelCase' | 'preserve';\n\t\t}) => {\n\t\t\tconst redactedUrl = redactDbUrl(options.db);\n\n\t\t\tconsole.log(`š Introspecting database: ${redactedUrl}`);\n\t\t\tconsole.log(` Schema: ${options.schemaName}`);\n\t\t\tif (options.exclude) {\n\t\t\t\tconsole.log(` Excluding: ${options.exclude}`);\n\t\t\t}\n\t\t\tconsole.log('');\n\n\t\t\ttry {\n\t\t\t\t// Connect to database\n\t\t\t\tconst { pool } = await createDbConnection(options.db);\n\n\t\t\t\ttry {\n\t\t\t\t\t// Import introspect from adapter-pgsql\n\t\t\t\t\tconst { introspect } = await import('@dbsp/adapter-pgsql');\n\n\t\t\t\t\t// Build introspection options from CLI flags\n\t\t\t\t\tconst excludePatterns = options.exclude\n\t\t\t\t\t\t? options.exclude.split(',').map((s) => s.trim())\n\t\t\t\t\t\t: undefined;\n\t\t\t\t\tconst includePatterns = options.include\n\t\t\t\t\t\t? options.include.split(',').map((s) => s.trim())\n\t\t\t\t\t\t: undefined;\n\n\t\t\t\t\t// Introspect the database directly (returns IntrospectedModelIR)\n\t\t\t\t\tconst model = await introspect(pool, {\n\t\t\t\t\t\tschema: options.schemaName,\n\t\t\t\t\t\t...(excludePatterns ? { exclude: excludePatterns } : {}),\n\t\t\t\t\t\t...(includePatterns ? { include: includePatterns } : {}),\n\t\t\t\t\t});\n\n\t\t\t\t\t// Report what we found\n\t\t\t\t\tconst tableCount = model.tables.size;\n\t\t\t\t\tconst relationCount = model.relations.size;\n\t\t\t\t\tconst hierarchyCount = model.hierarchies?.length ?? 0;\n\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`š Found ${tableCount} tables, ${relationCount} relations, ${hierarchyCount} hierarchies`,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Generate schema file ā pass metadata from introspection\n\t\t\t\t\tconst codegenOptions: SchemaCodegenOptions = {\n\t\t\t\t\t\tsourceUrl: options.db,\n\t\t\t\t\t\tincludeDbTypeComments: options.dbTypeComments,\n\t\t\t\t\t\tintrospectedAt: model.introspectedAt,\n\t\t\t\t\t\tdbCasing: options.dbCasing,\n\t\t\t\t\t};\n\n\t\t\t\t\tconst generated = generateSchemaFileWithDiagnostics(\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tcodegenOptions,\n\t\t\t\t\t);\n\t\t\t\t\tconst warnings = uniqueWarnings(generated.warnings);\n\t\t\t\t\tif (warnings.length > 0) {\n\t\t\t\t\t\treportWarnings(warnings);\n\t\t\t\t\t}\n\t\t\t\t\tconsole.log('');\n\n\t\t\t\t\t// Write output file\n\t\t\t\t\tconst outPath = resolve(process.cwd(), options.out);\n\t\t\t\t\tmkdirSync(dirname(outPath), { recursive: true });\n\t\t\t\t\twriteFileSync(outPath, generated.code, 'utf-8');\n\n\t\t\t\t\tconsole.log(`ā
Generated schema: ${outPath}`);\n\t\t\t\t\tconsole.log(` Tables: ${tableCount}`);\n\t\t\t\t\tconsole.log(` Relations: ${relationCount}`);\n\t\t\t\t} finally {\n\t\t\t\t\t// Close database connection\n\t\t\t\t\tawait pool.end();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tconsole.error(`ā ${message}`);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n","/**\n * Migrate Command ā Migration Infrastructure\n *\n * dbsp migrate dev - Generate migration from schema diff\n * dbsp migrate apply - Apply pending migrations\n * dbsp migrate rollback - Roll back applied migrations\n * dbsp migrate status - Show migration status\n */\n\nimport {\n\tcomparePgsqlDatabaseSchema,\n\tcreatePgsqlAdapter,\n\tensureMigrationsTable,\n\tescapeDiagnosticText,\n\tgenerateMigrationFile,\n\tgenerateMigrationSQL,\n\tgetAppliedMigrations,\n\tgetNextSchemaVersion,\n\tisDestructiveDown,\n\ttype MigrationRecord,\n\tparseMigrationFile,\n\trecordMigration,\n\tremoveMigrationRecord,\n\twithMigrationLock,\n} from '@dbsp/adapter-pgsql';\nimport { Command } from 'commander';\nimport type { Pool, PoolClient } from 'pg';\nimport {\n\tDEFAULT_MIGRATIONS_DIR,\n\tgenerateMigrationFilename,\n\ttype MigrationFile,\n\tscanMigrationFiles,\n\twriteMigrationFile,\n} from '../migration-file.js';\nimport { createDbConnection, redactDbUrl } from '../utils/db-utils.js';\nimport { loadSchema } from '../utils/schema-loader.js';\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Typed error for migration failures.\n * Distinguishes user-facing errors (validation, logic) from unexpected errors.\n */\nexport class MigrationError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'MigrationError';\n\t}\n}\n\n/**\n * Sanitize a pg error for user-facing output.\n *\n * PostgreSQL errors may carry schema/table/row details in their message text.\n * For pg errors (identifiable by SQLSTATE `.code`), we emit a sanitized message\n * keyed only by the SQLSTATE code. The raw message is available via DEBUG=dbsp.\n *\n * @param err - Any caught value\n * @returns An Error instance safe to display to the user\n */\nexport function sanitizePgError(err: unknown): Error {\n\tif (err instanceof Error) {\n\t\t// pg errors carry a SQLSTATE `.code` property\n\t\tconst code = (err as Error & { code?: string }).code;\n\t\tif (typeof code === 'string' && /^[0-9A-Z]{5}$/.test(code)) {\n\t\t\tif (process.env.DEBUG?.includes('dbsp')) {\n\t\t\t\tconsole.error(`[DEBUG] pg error detail: ${err.message}`);\n\t\t\t}\n\t\t\treturn new MigrationError(`Migration failed: database error ${code}`);\n\t\t}\n\t\treturn err;\n\t}\n\treturn new Error(String(err));\n}\n\n/**\n * DRY lifecycle wrapper: create pool ā run fn ā end pool on success or error.\n * Replaces the repeated try { ... } finally { pool.end() } pattern across commands.\n *\n * process.exit is called OUTSIDE the pool lifecycle so the lock-holding client\n * (from withMigrationLock) is always released before the process terminates.\n */\nexport async function withMigratePool<T>(\n\tdbUrl: string,\n\tfn: (pool: Pool) => Promise<T>,\n): Promise<T> {\n\tconst { pool } = await createDbConnection(dbUrl);\n\ttry {\n\t\treturn await fn(pool);\n\t} finally {\n\t\tlet endError: unknown;\n\t\ttry {\n\t\t\tawait pool.end();\n\t\t} catch (e) {\n\t\t\tendError = e;\n\t\t}\n\t\tif (endError !== undefined) {\n\t\t\t// Cleanup failure is non-fatal ā log it but don't mask the original error\n\t\t\tconsole.error(\n\t\t\t\t`Warning: pool.end() failed: ${endError instanceof Error ? endError.message : String(endError)}`,\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Top-level error handler for migrate commands.\n * Ensures process.exit is only called AFTER pool cleanup (via withMigratePool).\n */\nasync function runMigrateAction(fn: () => Promise<void>): Promise<void> {\n\ttry {\n\t\tawait fn();\n\t} catch (error) {\n\t\tif (error instanceof Error) {\n\t\t\tconsole.error(`ā Error: ${error.message}`);\n\t\t} else {\n\t\t\tconsole.error('ā Unknown error occurred');\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n\n/**\n * Returns true if a migration statement contains at least one executable SQL\n * line (non-empty, not a comment). Statements that consist entirely of blank\n * lines and `--` comment lines are skipped; statements that begin with a\n * comment header but also contain real SQL are kept (PostgreSQL ignores the\n * comment, so the header is harmless and preserves intent).\n */\nexport function hasExecutableSql(stmt: string): boolean {\n\treturn stmt.split('\\n').some((line) => {\n\t\tconst t = line.trim();\n\t\treturn t.length > 0 && !t.startsWith('--');\n\t});\n}\n\nexport interface ApplyOptions {\n\tdb: string;\n\tdir: string;\n\tdryRun?: boolean;\n}\n\nexport interface RollbackOptions {\n\tcount: number;\n\tdb: string;\n\tdir: string;\n\tforce?: boolean;\n}\n\nexport interface MigrateDeps {\n\twithMigratePool?: <T>(\n\t\tdbUrl: string,\n\t\tfn: (pool: Pool) => Promise<T>,\n\t) => Promise<T>;\n\tensureMigrationsTable?: (pool: Pool) => Promise<void>;\n\twithMigrationLock?: <T>(\n\t\tpool: Pool,\n\t\tfn: (client: PoolClient) => Promise<T>,\n\t) => Promise<T>;\n\tgetAppliedMigrations?: (pool: Pool) => Promise<readonly MigrationRecord[]>;\n\tscanMigrationFiles?: (dir: string) => readonly MigrationFile[];\n\tparseMigrationFile?: typeof parseMigrationFile;\n\tgetNextSchemaVersion?: (pool: Pool) => Promise<number>;\n\trecordMigration?: (\n\t\tpool: Pool,\n\t\tname: string,\n\t\tchecksum: string,\n\t\tschemaVersion: number,\n\t\tdestructive: boolean,\n\t) => Promise<void>;\n\tremoveMigrationRecord?: (pool: Pool, name: string) => Promise<void>;\n\tisDestructiveDown?: (downStatements: readonly string[]) => boolean;\n}\n\nconst defaultMigrateDeps: Required<MigrateDeps> = {\n\twithMigratePool,\n\tensureMigrationsTable,\n\twithMigrationLock,\n\tgetAppliedMigrations,\n\tscanMigrationFiles,\n\tparseMigrationFile,\n\tgetNextSchemaVersion,\n\trecordMigration,\n\tremoveMigrationRecord,\n\tisDestructiveDown,\n};\n\nfunction resolveMigrateDeps(deps?: MigrateDeps): Required<MigrateDeps> {\n\treturn { ...defaultMigrateDeps, ...deps };\n}\n\nexport async function runApply(\n\toptions: ApplyOptions,\n\tdeps?: MigrateDeps,\n): Promise<void> {\n\tconst d = resolveMigrateDeps(deps);\n\n\tconsole.log('š Applying migrations');\n\tconsole.log(` Database: ${redactDbUrl(options.db)}`);\n\tconsole.log(` Directory: ${options.dir}`);\n\tconsole.log('');\n\n\tawait d.withMigratePool(options.db, async (pool) => {\n\t\t// Ensure tracking table exists before acquiring lock\n\t\tawait d.ensureMigrationsTable(pool);\n\n\t\tawait d.withMigrationLock(pool, async (client) => {\n\t\t\t// Get applied migrations on the lock-holding client\n\t\t\tconst applied = await d.getAppliedMigrations(client as unknown as Pool);\n\t\t\tconst appliedMap = new Map(applied.map((m) => [m.name, m.checksum]));\n\n\t\t\t// Scan migration files\n\t\t\tconst files = d.scanMigrationFiles(options.dir);\n\n\t\t\tif (files.length === 0) {\n\t\t\t\tconsole.log(`No migration files found in ${options.dir}`);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Validate checksums for already-applied migrations\n\t\t\tfor (const file of files) {\n\t\t\t\tconst existingChecksum = appliedMap.get(file.name);\n\t\t\t\tif (\n\t\t\t\t\texistingChecksum !== undefined &&\n\t\t\t\t\texistingChecksum !== file.checksum\n\t\t\t\t) {\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t`Checksum mismatch for ${file.name}\\n` +\n\t\t\t\t\t\t\t` Expected: ${existingChecksum}\\n` +\n\t\t\t\t\t\t\t` Got: ${file.checksum}\\n` +\n\t\t\t\t\t\t\t'\\nMigration file has been tampered with after being applied.',\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Find pending migrations\n\t\t\tconst pending = files.filter((f) => !appliedMap.has(f.name));\n\n\t\t\tif (pending.length === 0) {\n\t\t\t\tconsole.log('ā
All migrations already applied.');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (options.dryRun) {\n\t\t\t\tconsole.log(`${pending.length} pending migration(s):`);\n\t\t\t\tfor (const file of pending) {\n\t\t\t\t\tconsole.log(` - ${file.name}`);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Apply each pending migration atomically (DDL + record in one transaction)\n\t\t\tlet appliedCount = 0;\n\t\t\tfor (const file of pending) {\n\t\t\t\tconsole.log(` Applying: ${file.name}...`);\n\n\t\t\t\t// Parse UP section from file\n\t\t\t\tconst parsed = d.parseMigrationFile(file.content);\n\t\t\t\tconst statements = parsed.upStatements.filter(hasExecutableSql);\n\n\t\t\t\t// Determine version and destructive flag before the transaction\n\t\t\t\t// (read from the lock-held client so we see a consistent view)\n\t\t\t\tconst version = await d.getNextSchemaVersion(client as unknown as Pool);\n\t\t\t\tconst destructive = parsed.destructive === true;\n\n\t\t\t\t// Atomic: DDL + record in ONE transaction on the lock-holding client\n\t\t\t\ttry {\n\t\t\t\t\tawait client.query('BEGIN');\n\n\t\t\t\t\tfor (const stmt of statements) {\n\t\t\t\t\t\tawait client.query(stmt);\n\t\t\t\t\t}\n\n\t\t\t\t\tawait d.recordMigration(\n\t\t\t\t\t\tclient as unknown as Pool,\n\t\t\t\t\t\tfile.name,\n\t\t\t\t\t\tfile.checksum,\n\t\t\t\t\t\tversion,\n\t\t\t\t\t\tdestructive,\n\t\t\t\t\t);\n\n\t\t\t\t\tawait client.query('COMMIT');\n\t\t\t\t} catch (applyError) {\n\t\t\t\t\tlet rollbackError: unknown;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait client.query('ROLLBACK');\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\trollbackError = e;\n\t\t\t\t\t}\n\t\t\t\t\tconst primary = sanitizePgError(applyError);\n\t\t\t\t\tif (rollbackError !== undefined) {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t` Note: rollback also failed: ${sanitizePgError(rollbackError).message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tthrow primary;\n\t\t\t\t}\n\n\t\t\t\tappliedCount++;\n\t\t\t\tconsole.log(` ā
Applied: ${file.name}`);\n\t\t\t}\n\n\t\t\tconsole.log(`\\nā
${appliedCount} migration(s) applied successfully.`);\n\t\t});\n\t});\n}\n\nexport async function runRollback(\n\toptions: RollbackOptions,\n\tdeps?: MigrateDeps,\n): Promise<void> {\n\tconst d = resolveMigrateDeps(deps);\n\n\tconsole.log(`āŖ Rolling back ${options.count} migration(s)`);\n\tconsole.log(` Database: ${redactDbUrl(options.db)}`);\n\tconsole.log(` Directory: ${options.dir}`);\n\tconsole.log('');\n\n\tawait d.withMigratePool(options.db, async (pool) => {\n\t\tawait d.ensureMigrationsTable(pool);\n\n\t\tawait d.withMigrationLock(pool, async (client) => {\n\t\t\t// Get applied migrations on the lock-holding client\n\t\t\tconst applied = await d.getAppliedMigrations(client as unknown as Pool);\n\t\t\tconst sortedDesc = [...applied].sort((a, b) =>\n\t\t\t\tb.name.localeCompare(a.name),\n\t\t\t);\n\n\t\t\t// SC-18: Validate count\n\t\t\tif (options.count > sortedDesc.length) {\n\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t`Cannot roll back ${options.count} migration(s) ā only ${sortedDesc.length} applied`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst toRollback = sortedDesc.slice(0, options.count);\n\n\t\t\t// Load migration files from disk\n\t\t\tconst files = d.scanMigrationFiles(options.dir);\n\t\t\tconst fileMap = new Map(files.map((f) => [f.name, f]));\n\n\t\t\tlet rolledBack = 0;\n\t\t\tfor (const record of toRollback) {\n\t\t\t\tconst file = fileMap.get(record.name);\n\t\t\t\tif (!file) {\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t`Migration file not found on disk: ${record.name}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// SC-17: Verify checksum\n\t\t\t\tif (file.checksum !== record.checksum) {\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t`Checksum mismatch for ${record.name}\\n` +\n\t\t\t\t\t\t\t` Expected: ${record.checksum}\\n` +\n\t\t\t\t\t\t\t` Got: ${file.checksum}\\n` +\n\t\t\t\t\t\t\t'\\nMigration file has been modified since it was applied.',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Parse DOWN section\n\t\t\t\tconst parsed = d.parseMigrationFile(file.content);\n\n\t\t\t\t// SC-10/ERR-01: No DOWN section\n\t\t\t\tif (!parsed.hasDown) {\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t`Migration ${record.name} has no DOWN section\\n` +\n\t\t\t\t\t\t\t' Cannot roll back a migration without a DOWN section.',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// SC-11/ERR-04: Empty DOWN section\n\t\t\t\tconst downStmts = parsed.downStatements.filter(hasExecutableSql);\n\t\t\t\tif (downStmts.length === 0 && !options.force) {\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t`Migration ${record.name} has an empty DOWN section\\n` +\n\t\t\t\t\t\t\t' Use --force to roll back anyway.',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// SC-19: Metadata-driven destructive rollback guard\n\t\t\t\tconst safeHeaderContradictedByDown =\n\t\t\t\t\tparsed.destructive === false && d.isDestructiveDown(downStmts);\n\t\t\t\tif (\n\t\t\t\t\t(parsed.destructive !== false || safeHeaderContradictedByDown) &&\n\t\t\t\t\t!options.force\n\t\t\t\t) {\n\t\t\t\t\tif (parsed.destructive === true) {\n\t\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t\t`Migration ${record.name} has destructive DOWN operations\\n` +\n\t\t\t\t\t\t\t\t' Use --force to proceed with destructive rollback.',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (safeHeaderContradictedByDown) {\n\t\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t\t`Migration ${record.name} is marked non-destructive but its DOWN section contains an obvious destructive statement\\n` +\n\t\t\t\t\t\t\t\t' Re-generate the migration with accurate dbsp metadata or pass --force.',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t`Migration ${record.name} is unmarked or legacy\\n` +\n\t\t\t\t\t\t\t' Re-generate the migration with dbsp metadata or pass --force.',\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Atomic: DOWN SQL + remove record in ONE transaction on the lock-holding client\n\t\t\t\tif (downStmts.length > 0 || options.force) {\n\t\t\t\t\tconsole.log(` Rolling back: ${record.name}...`);\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tawait client.query('BEGIN');\n\n\t\t\t\t\tfor (const stmt of downStmts) {\n\t\t\t\t\t\tawait client.query(stmt);\n\t\t\t\t\t}\n\n\t\t\t\t\tawait d.removeMigrationRecord(client as unknown as Pool, record.name);\n\n\t\t\t\t\tawait client.query('COMMIT');\n\t\t\t\t} catch (rollbackError) {\n\t\t\t\t\tlet rollbackCleanupError: unknown;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait client.query('ROLLBACK');\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\trollbackCleanupError = e;\n\t\t\t\t\t}\n\t\t\t\t\tconst primary = sanitizePgError(rollbackError);\n\t\t\t\t\tif (rollbackCleanupError !== undefined) {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t` Note: rollback also failed: ${sanitizePgError(rollbackCleanupError).message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tthrow primary;\n\t\t\t\t}\n\n\t\t\t\trolledBack++;\n\t\t\t\tconsole.log(` ā
Rolled back: ${record.name}`);\n\t\t\t}\n\n\t\t\tconsole.log(`\\nā
${rolledBack} migration(s) rolled back successfully.`);\n\t\t});\n\t});\n}\n\nfunction runRollbackCommand(\n\tcountArg: string,\n\toptions: { db: string; dir: string; force?: boolean },\n): Promise<void> {\n\tconst count = Number.parseInt(countArg, 10);\n\tif (Number.isNaN(count) || count < 1) {\n\t\tconsole.error('ā Count must be a positive integer');\n\t\tprocess.exit(1);\n\t}\n\n\treturn runMigrateAction(async () => {\n\t\tawait runRollback({ count, ...options });\n\t});\n}\n\n// ============================================================================\n// Subcommands\n// ============================================================================\n\nconst devCommand = new Command('dev')\n\t.description('Generate a migration from schema changes')\n\t.option(\n\t\t'-s, --schema <path>',\n\t\t'Path to schema file (default: dbsp.schema.ts)',\n\t)\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--schema-name <name>', 'Database schema name (default: public)')\n\t.option('--dir <path>', 'Migrations directory', DEFAULT_MIGRATIONS_DIR)\n\t.option('-n, --name <description>', 'Migration description', 'migration')\n\t.option('--allow-destructive', 'Include destructive changes (drops)')\n\t.action(\n\t\t(options: {\n\t\t\tschema?: string;\n\t\t\tdb: string;\n\t\t\tschemaName?: string;\n\t\t\tdir: string;\n\t\t\tname: string;\n\t\t\tallowDestructive?: boolean;\n\t\t}) =>\n\t\t\trunMigrateAction(async () => {\n\t\t\t\tconst schemaPath = options.schema ?? 'dbsp.schema.ts';\n\n\t\t\t\tconsole.log(`š Generating migration: ${schemaPath}`);\n\t\t\t\tconsole.log(` Database: ${redactDbUrl(options.db)}`);\n\t\t\t\tconsole.log('');\n\n\t\t\t\tconst loaded = await loadSchema(schemaPath);\n\t\t\t\tconst schemaModel = loaded.model;\n\n\t\t\t\tawait withMigratePool(options.db, async (pool) => {\n\t\t\t\t\tconst adapter = createPgsqlAdapter(pool);\n\t\t\t\t\tconst diff = await comparePgsqlDatabaseSchema(adapter, schemaModel, {\n\t\t\t\t\t\t...(options.schemaName ? { schema: options.schemaName } : {}),\n\t\t\t\t\t\t...(loaded.dbCasing ? { dbCasing: loaded.dbCasing } : {}),\n\t\t\t\t\t\tonExpressionCanonicalizationWarning: (warning) =>\n\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t`ā ļø [${warning.kind} ${escapeDiagnosticText(warning.table)}.${escapeDiagnosticText(warning.name)}] ${warning.message}`,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t});\n\n\t\t\t\t\tif (diff.changes.length === 0) {\n\t\t\t\t\t\tconsole.log('ā
No changes detected ā database matches schema.');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check for destructive changes\n\t\t\t\t\tif (diff.hasDestructive && !options.allowDestructive) {\n\t\t\t\t\t\tconst destructive = diff.changes.filter((c) => c.destructive);\n\t\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t\t`${destructive.length} destructive change(s) detected:\\n` +\n\t\t\t\t\t\t\t\tdestructive.map((c) => ` - ${c.details}`).join('\\n') +\n\t\t\t\t\t\t\t\t'\\n\\nUse --allow-destructive to include these changes.',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst sqlOptions = {\n\t\t\t\t\t\tincludeDestructive: options.allowDestructive ?? false,\n\t\t\t\t\t\t...(options.schemaName ? { schemaName: options.schemaName } : {}),\n\t\t\t\t\t};\n\n\t\t\t\t\tconst statements = generateMigrationSQL(diff, sqlOptions);\n\n\t\t\t\t\tif (statements.length === 0) {\n\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t'ā
No migration needed ā all changes are non-actionable.',\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Generate migration file with UP + DOWN sections\n\t\t\t\t\tconst existingFiles = scanMigrationFiles(options.dir).map(\n\t\t\t\t\t\t(f) => f.name,\n\t\t\t\t\t);\n\t\t\t\t\tconst filename = generateMigrationFilename(\n\t\t\t\t\t\texistingFiles,\n\t\t\t\t\t\toptions.name,\n\t\t\t\t\t);\n\t\t\t\t\tconst content = generateMigrationFile(diff, {\n\t\t\t\t\t\t...sqlOptions,\n\t\t\t\t\t\tname: filename,\n\t\t\t\t\t});\n\n\t\t\t\t\tconst file = writeMigrationFile(options.dir, filename, content);\n\n\t\t\t\t\tconsole.log(`ā
Migration created: ${file.path}`);\n\t\t\t\t\tconsole.log(` Statements: ${statements.length}`);\n\t\t\t\t\tconsole.log(` Checksum: ${file.checksum.slice(0, 12)}...`);\n\t\t\t\t});\n\t\t\t}),\n\t);\n\nconst applyCommand = new Command('apply')\n\t.description('Apply pending migrations')\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--dir <path>', 'Migrations directory', DEFAULT_MIGRATIONS_DIR)\n\t.option('--dry-run', 'Show pending migrations without applying')\n\t.action((options: ApplyOptions) =>\n\t\trunMigrateAction(async () => {\n\t\t\tawait runApply(options);\n\t\t}),\n\t);\n\nconst rollbackCommand = new Command('rollback')\n\t.description('Roll back applied migrations')\n\t.argument('<count>', 'Number of migrations to roll back')\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--dir <path>', 'Migrations directory', DEFAULT_MIGRATIONS_DIR)\n\t.option('--force', 'Force rollback of destructive or empty DOWN migrations')\n\t.action(runRollbackCommand);\n\nconst statusCommand = new Command('status')\n\t.description('Show migration status')\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--dir <path>', 'Migrations directory', DEFAULT_MIGRATIONS_DIR)\n\t.option('--json', 'Output as JSON')\n\t.action((options: { db: string; dir: string; json?: boolean }) =>\n\t\trunMigrateAction(async () => {\n\t\t\tawait withMigratePool(options.db, async (pool) => {\n\t\t\t\tawait ensureMigrationsTable(pool);\n\n\t\t\t\tconst applied = await getAppliedMigrations(pool);\n\t\t\t\tconst appliedMap = new Map(applied.map((m) => [m.name, m]));\n\n\t\t\t\tconst files = scanMigrationFiles(options.dir);\n\n\t\t\t\tconst statuses: Array<{\n\t\t\t\t\tname: string;\n\t\t\t\t\tstatus: 'pending' | 'applied' | 'checksum_mismatch' | 'missing_file';\n\t\t\t\t\tappliedAt?: Date;\n\t\t\t\t}> = files.map((file) => {\n\t\t\t\t\tconst record = appliedMap.get(file.name);\n\t\t\t\t\tif (record === undefined) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tname: file.name,\n\t\t\t\t\t\t\tstatus: 'pending' as const,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tif (record.checksum !== file.checksum) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tname: file.name,\n\t\t\t\t\t\t\tstatus: 'checksum_mismatch' as const,\n\t\t\t\t\t\t\tappliedAt: record.appliedAt,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tname: file.name,\n\t\t\t\t\t\tstatus: 'applied' as const,\n\t\t\t\t\t\tappliedAt: record.appliedAt,\n\t\t\t\t\t};\n\t\t\t\t});\n\n\t\t\t\t// Also show applied migrations that don't have files anymore\n\t\t\t\tfor (const record of applied) {\n\t\t\t\t\tif (!files.some((f) => f.name === record.name)) {\n\t\t\t\t\t\tstatuses.push({\n\t\t\t\t\t\t\tname: record.name,\n\t\t\t\t\t\t\tstatus: 'missing_file' as const,\n\t\t\t\t\t\t\tappliedAt: record.appliedAt,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (options.json) {\n\t\t\t\t\tconsole.log(JSON.stringify(statuses, null, 2));\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log('Migration Status');\n\t\t\t\t\tconsole.log(` Database: ${redactDbUrl(options.db)}`);\n\t\t\t\t\tconsole.log(` Directory: ${options.dir}`);\n\t\t\t\t\tconsole.log('');\n\n\t\t\t\t\tif (statuses.length === 0) {\n\t\t\t\t\t\tconsole.log('No migrations found.');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor (const s of statuses) {\n\t\t\t\t\t\t\tconst icon =\n\t\t\t\t\t\t\t\ts.status === 'applied'\n\t\t\t\t\t\t\t\t\t? 'ā
'\n\t\t\t\t\t\t\t\t\t: s.status === 'pending'\n\t\t\t\t\t\t\t\t\t\t? 'ā³'\n\t\t\t\t\t\t\t\t\t\t: s.status === 'checksum_mismatch'\n\t\t\t\t\t\t\t\t\t\t\t? 'ā ļø'\n\t\t\t\t\t\t\t\t\t\t\t: 'ā';\n\t\t\t\t\t\t\tconst detail =\n\t\t\t\t\t\t\t\t'appliedAt' in s && s.appliedAt\n\t\t\t\t\t\t\t\t\t? ` (applied: ${s.appliedAt.toISOString()})`\n\t\t\t\t\t\t\t\t\t: '';\n\t\t\t\t\t\t\tconsole.log(` ${icon} ${s.name} ā ${s.status}${detail}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst pendingCount = statuses.filter(\n\t\t\t\t\t\t\t(s) => s.status === 'pending',\n\t\t\t\t\t\t).length;\n\t\t\t\t\t\tconst appliedCount = statuses.filter(\n\t\t\t\t\t\t\t(s) => s.status === 'applied',\n\t\t\t\t\t\t).length;\n\n\t\t\t\t\t\tconsole.log('');\n\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t`Total: ${statuses.length} | Applied: ${appliedCount} | Pending: ${pendingCount}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}),\n\t);\n\n// ============================================================================\n// Main Command\n// ============================================================================\n\nexport const migrateCommand = new Command('migrate')\n\t.description('Database migration management')\n\t.addCommand(devCommand)\n\t.addCommand(applyCommand)\n\t.addCommand(rollbackCommand)\n\t.addCommand(statusCommand);\n","/**\n * Migration File ā File I/O, naming conventions, checksums.\n *\n * Handles reading/writing migration SQL files and computing\n * SHA-256 checksums for tamper detection.\n */\n\nimport { createHash } from 'node:crypto';\nimport {\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\twriteFileSync,\n} from 'node:fs';\nimport { join, resolve } from 'node:path';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface MigrationFile {\n\t/** Filename (e.g., \"0001_create_users.sql\") */\n\treadonly name: string;\n\t/** Full path to the file */\n\treadonly path: string;\n\t/** SQL content */\n\treadonly content: string;\n\t/** SHA-256 checksum of content */\n\treadonly checksum: string;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Default directory for migration files */\nexport const DEFAULT_MIGRATIONS_DIR = 'migrations';\n\n/** Migration file naming pattern: NNNN_description.sql */\nconst MIGRATION_FILENAME_PATTERN = /^\\d{4}_[\\w-]+\\.sql$/;\n\n// ============================================================================\n// Checksum\n// ============================================================================\n\n/**\n * Compute SHA-256 checksum of content.\n */\nexport function computeChecksum(content: string): string {\n\treturn createHash('sha256').update(content, 'utf-8').digest('hex');\n}\n\n// ============================================================================\n// File Naming\n// ============================================================================\n\n/**\n * Generate the next migration filename.\n *\n * @param existingFiles - List of existing migration filenames\n * @param description - Human-readable description (e.g., \"create_users\")\n * @returns Filename (e.g., \"0001_create_users.sql\")\n */\nexport function generateMigrationFilename(\n\texistingFiles: readonly string[],\n\tdescription: string,\n): string {\n\tconst maxNum = existingFiles.reduce((max, f) => {\n\t\tconst match = f.match(/^(\\d{4})/);\n\t\treturn match?.[1] ? Math.max(max, Number.parseInt(match[1], 10)) : max;\n\t}, 0);\n\n\tconst nextNum = String(maxNum + 1).padStart(4, '0');\n\tconst sanitized = description\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9_-]/g, '_')\n\t\t.replace(/_+/g, '_')\n\t\t.replace(/^_|_$/g, '');\n\n\treturn `${nextNum}_${sanitized || 'migration'}.sql`;\n}\n\n// ============================================================================\n// File I/O\n// ============================================================================\n\n/**\n * Ensure the migrations directory exists.\n */\nexport function ensureMigrationsDir(dir: string): string {\n\tconst fullPath = resolve(dir);\n\tif (!existsSync(fullPath)) {\n\t\tmkdirSync(fullPath, { recursive: true });\n\t}\n\treturn fullPath;\n}\n\n/**\n * Scan migrations directory and return all valid migration files,\n * sorted by name (lexicographic = chronological with zero-padded numbers).\n */\nexport function scanMigrationFiles(dir: string): readonly MigrationFile[] {\n\tconst fullPath = resolve(dir);\n\tif (!existsSync(fullPath)) {\n\t\treturn [];\n\t}\n\n\tconst entries = readdirSync(fullPath)\n\t\t.filter((f) => MIGRATION_FILENAME_PATTERN.test(f))\n\t\t.sort();\n\n\treturn entries.map((name) => {\n\t\tconst filePath = join(fullPath, name);\n\t\tconst content = readFileSync(filePath, 'utf-8');\n\t\treturn {\n\t\t\tname,\n\t\t\tpath: filePath,\n\t\t\tcontent,\n\t\t\tchecksum: computeChecksum(content),\n\t\t};\n\t});\n}\n\n/**\n * Write a migration file to the migrations directory.\n *\n * @returns The created MigrationFile\n */\nexport function writeMigrationFile(\n\tdir: string,\n\tfilename: string,\n\tcontent: string,\n): MigrationFile {\n\tconst fullDir = ensureMigrationsDir(dir);\n\tconst filePath = join(fullDir, filename);\n\twriteFileSync(filePath, content, 'utf-8');\n\n\treturn {\n\t\tname: filename,\n\t\tpath: filePath,\n\t\tcontent,\n\t\tchecksum: computeChecksum(content),\n\t};\n}\n","/**\n * dbsp plan ā prove a transition and, unless previewing, retain it for a later\n * apply command. This command intentionally stops before execution.\n */\n\nimport {\n\tacquirePgTransitionClient,\n\tcreatePgExecutionContract,\n\tcreatePgsqlAdapter,\n\tcreatePgTransitionLessor,\n\tcreatePgTransitionPack,\n\tcreatePgTransitionRunPersister,\n\tensureTransitionJournal,\n\tescapeDiagnosticText,\n\tPgExecutionContractDerivationError,\n\tpgTargetIdentityMismatch,\n\treadPgExecutionTargetFromClient,\n\treadPgObservationContextFromLessor,\n} from '@dbsp/adapter-pgsql';\nimport {\n\tacquireTransitionLease,\n\tbindExecutionContract,\n\tcreateComparator,\n\tcreatePackRegistry,\n\tcreateProver,\n\tcreateTransitionRunMetadata,\n\ttype InProcessProvenPlan,\n\ttype PackRegistry,\n} from '@dbsp/core';\nimport type {\n\tCompareOutcome,\n\tExecutionContract,\n\tModelIR,\n\tObservationContext,\n\tPlanAssessment,\n\tPostgreSqlObservationTargetIdentity,\n\tTransitionRunMetadata,\n\tTransitionSessionClient,\n} from '@dbsp/types';\nimport { Command } from 'commander';\nimport type { Pool } from 'pg';\nimport { createDbConnection } from '../utils/db-utils.js';\nimport { type LoadedSchema, loadSchema } from '../utils/schema-loader.js';\n\nexport type PlanFormat = 'sql' | 'json';\nexport type PlanPersistenceState = boolean | 'indeterminate';\n\nexport interface PlanOptions {\n\treadonly db: string;\n\treadonly schemaFile: string;\n\treadonly schema?: string;\n\treadonly dryRun?: boolean;\n\treadonly format?: PlanFormat;\n}\n\nexport interface PlanResult {\n\treadonly compareKind: CompareOutcome['kind'];\n\treadonly proveKind: 'proven' | 'no-drift' | 'blocked' | 'inapplicable';\n\treadonly assessment: PlanAssessment;\n\t/** true is durable, false was not attempted, and indeterminate may have committed. */\n\treadonly persisted: PlanPersistenceState;\n\treadonly runId: string | null;\n\treadonly planDigest: string | null;\n\treadonly plan?: InProcessProvenPlan;\n\treadonly sql?: string;\n}\n\nexport class PlanPersistenceIndeterminateError extends Error {\n\treadonly runId: string;\n\treadonly result: PlanResult;\n\treadonly persistenceError: unknown;\n\treadonly cleanup: CleanupFailure;\n\n\tconstructor(\n\t\tresult: PlanResult,\n\t\tpersistenceError: unknown,\n\t\tcleanup: CleanupFailure = noCleanupFailure,\n\t) {\n\t\tconst cause =\n\t\t\tcleanup.kind === 'failed'\n\t\t\t\t? new AggregateError(\n\t\t\t\t\t\t[persistenceError, cleanup.error],\n\t\t\t\t\t\t'persistence and connection release both failed',\n\t\t\t\t\t)\n\t\t\t\t: persistenceError;\n\t\tsuper(\n\t\t\t`persistence indeterminate; inspect run ${result.runId}: ${escapeDiagnosticText(describeThrown(persistenceError))}`,\n\t\t\t{ cause },\n\t\t);\n\t\tthis.name = 'PlanPersistenceIndeterminateError';\n\t\tthis.runId = result.runId ?? '';\n\t\tthis.result = result;\n\t\tthis.persistenceError = persistenceError;\n\t\tthis.cleanup = cleanup;\n\t}\n}\n\n/** A completed plan outcome whose connection release failed afterwards. */\nexport class PlanCleanupError extends Error {\n\tconstructor(\n\t\treadonly result: PlanResult,\n\t\treadonly cleanupError: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`connection release failed after the plan outcome was determined: ${escapeDiagnosticText(describeThrown(cleanupError))}`,\n\t\t\t{ cause: cleanupError },\n\t\t);\n\t\tthis.name = 'PlanCleanupError';\n\t}\n}\n\n/** A planning failure whose declared connection release also failed. */\nclass PlanOperationAndCleanupError extends AggregateError {\n\tconstructor(\n\t\treadonly operationError: unknown,\n\t\treadonly cleanupError: unknown,\n\t) {\n\t\tsuper(\n\t\t\t[operationError, cleanupError],\n\t\t\t'planning and connection release both failed',\n\t\t\t{ cause: operationError },\n\t\t);\n\t\tthis.name = 'PlanOperationAndCleanupError';\n\t}\n}\n\ntype PlanPool = Pool;\n\n/** A release rejection is distinct from its rejection value, including undefined. */\ntype CleanupFailure =\n\t| { readonly kind: 'not-failed' }\n\t| { readonly kind: 'failed'; readonly error: unknown };\n\nconst noCleanupFailure: CleanupFailure = { kind: 'not-failed' };\n\n/**\n * A planning connection together with the action that returns its resource.\n *\n * The caller that supplies the pool decides whether it is owned, shared, or\n * otherwise managed; runPlan only invokes this declared release path.\n */\nexport interface PlanConnection {\n\treadonly pool: PlanPool;\n\treadonly release: () => Promise<void>;\n}\n\nexport interface PlanDeps {\n\treadonly createDbConnection: (db: string) => Promise<PlanConnection>;\n\treadonly loadSchema: (path: string) => Promise<LoadedSchema>;\n\treadonly ensureTransitionJournal: (pool: PlanPool) => Promise<void>;\n\treadonly captureTargetIdentity: (\n\t\tpool: PlanPool,\n\t\tschema: string | undefined,\n\t) => Promise<PostgreSqlObservationTargetIdentity>;\n\treadonly loadCurrent: (\n\t\tpool: PlanPool,\n\t\tschema: string | undefined,\n\t\texpectedTargetIdentity: PostgreSqlObservationTargetIdentity,\n\t) => Promise<ModelIR>;\n\treadonly readContext: (\n\t\tpool: PlanPool,\n\t\tschema?: string,\n\t\texpectedTargetIdentity?: PostgreSqlObservationTargetIdentity,\n\t) => Promise<ObservationContext>;\n\treadonly createPlanner: (loaded: LoadedSchema) => PlanPlanner;\n\treadonly persist: (\n\t\tpool: PlanPool,\n\t\trun: TransitionRunMetadata,\n\t\tplan: InProcessProvenPlan,\n\t) => Promise<void>;\n\treadonly buildExecutionContract: (\n\t\tpool: PlanPool,\n\t\tschema: string | undefined,\n\t\tplan: InProcessProvenPlan,\n\t\texpectedTargetIdentity: PostgreSqlObservationTargetIdentity,\n\t) => Promise<ExecutionContract>;\n}\n\nexport interface PlanPlanner {\n\treadonly compare: (\n\t\tdesired: ModelIR,\n\t\tcurrent: ModelIR,\n\t\tcontext: ObservationContext,\n\t) => CompareOutcome;\n\treadonly prove: (\n\t\tcompare: CompareOutcome,\n\t\tpool: PlanPool,\n\t\tcontext: ObservationContext,\n\t) => ReturnType<ReturnType<typeof createProver>['prove']>;\n\treadonly render: (\n\t\tplan: InProcessProvenPlan,\n\t\tcontext: ObservationContext,\n\t) => string;\n}\n\nfunction equivalenceContext(context: ObservationContext) {\n\treturn {\n\t\tengine: context.engine,\n\t\t...(context.databaseId ? { databaseId: context.databaseId } : {}),\n\t\t...(context.targetSchema ? { targetSchema: context.targetSchema } : {}),\n\t\t...(context.searchPath ? { searchPath: context.searchPath } : {}),\n\t\tproofObservationContext: context,\n\t};\n}\n\n/** The only planning-time namespace derivation; apply uses the stored clause. */\nexport function executionTargetNamespaces(\n\tplan: InProcessProvenPlan,\n\tfallbackSchema: string | undefined,\n): readonly string[] {\n\tconst namespaces = [\n\t\t...new Set(\n\t\t\tplan.steps.map((step) => {\n\t\t\t\tconst payload = step.operation.payload;\n\t\t\t\tif (\n\t\t\t\t\tpayload === null ||\n\t\t\t\t\ttypeof payload !== 'object' ||\n\t\t\t\t\tArray.isArray(payload) ||\n\t\t\t\t\ttypeof (payload as Record<string, unknown>).schema !== 'string'\n\t\t\t\t)\n\t\t\t\t\tthrow new PgExecutionContractDerivationError(\n\t\t\t\t\t\tstep.operation.ref,\n\t\t\t\t\t\tstep.operation.operationKind.name,\n\t\t\t\t\t\t'has no derivable target namespace',\n\t\t\t\t\t);\n\t\t\t\treturn (payload as Record<string, unknown>).schema as string;\n\t\t\t}),\n\t\t),\n\t];\n\tif (namespaces.length === 0 && fallbackSchema !== undefined)\n\t\tnamespaces.push(fallbackSchema);\n\treturn namespaces;\n}\n\n/** Build the PostgreSQL contract after resolving the plan's physical target. */\nexport async function buildPgExecutionContract(\n\tpool: PlanPool,\n\tschema: string | undefined,\n\tplan: InProcessProvenPlan,\n\texpectedTargetIdentity: PostgreSqlObservationTargetIdentity,\n): Promise<ExecutionContract> {\n\tconst lease = await acquireTransitionLease(createPgTransitionLessor(pool));\n\ttry {\n\t\tconst target = await readPgExecutionTargetFromClient(\n\t\t\tlease.session,\n\t\t\texecutionTargetNamespaces(plan, schema),\n\t\t);\n\t\tconst mismatch = pgTargetIdentityMismatch(\n\t\t\texpectedTargetIdentity,\n\t\t\ttarget.identity,\n\t\t);\n\t\tif (mismatch) {\n\t\t\tthrow new Error(\n\t\t\t\t`PostgreSQL target identity changed before plan persistence: ${mismatch}`,\n\t\t\t);\n\t\t}\n\t\treturn createPgExecutionContract(\n\t\t\tplan,\n\t\t\ttarget.identity,\n\t\t\ttarget.sessionProvenance,\n\t\t);\n\t} finally {\n\t\tawait lease.release();\n\t}\n}\n\nconst defaultPlanDeps: PlanDeps = {\n\tasync createDbConnection(db) {\n\t\tconst { pool } = await createDbConnection(db);\n\t\treturn { pool, release: () => pool.end() };\n\t},\n\tloadSchema,\n\tasync ensureTransitionJournal(pool) {\n\t\tconst lease = await acquireTransitionLease(createPgTransitionLessor(pool));\n\t\ttry {\n\t\t\tawait ensureTransitionJournal(lease.session);\n\t\t} finally {\n\t\t\tawait lease.release();\n\t\t}\n\t},\n\tasync captureTargetIdentity(pool, schema) {\n\t\tconst lease = await acquireTransitionLease(createPgTransitionLessor(pool));\n\t\ttry {\n\t\t\treturn (\n\t\t\t\tawait readPgExecutionTargetFromClient(lease.session, [\n\t\t\t\t\tschema ?? 'public',\n\t\t\t\t])\n\t\t\t).identity;\n\t\t} finally {\n\t\t\tawait lease.release();\n\t\t}\n\t},\n\tasync loadCurrent(pool, schema, expectedTargetIdentity) {\n\t\tconst lease = await acquirePgTransitionClient(pool);\n\t\ttry {\n\t\t\tconst observed = await readPgExecutionTargetFromClient(\n\t\t\t\tlease.client as unknown as TransitionSessionClient,\n\t\t\t\t[schema ?? 'public'],\n\t\t\t);\n\t\t\tconst mismatch = pgTargetIdentityMismatch(\n\t\t\t\texpectedTargetIdentity,\n\t\t\t\tobserved.identity,\n\t\t\t);\n\t\t\tif (mismatch) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`PostgreSQL introspection target identity does not match the captured target: ${mismatch}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn await createPgsqlAdapter(lease.client, {\n\t\t\t\tborrowedClient: true,\n\t\t\t}).introspect(schema === undefined ? {} : { schema });\n\t\t} finally {\n\t\t\tlease.release();\n\t\t}\n\t},\n\tasync readContext(pool, schema, expectedTargetIdentity) {\n\t\treturn readPgObservationContextFromLessor(\n\t\t\tcreatePgTransitionLessor(pool),\n\t\t\tschema,\n\t\t\tundefined,\n\t\t\texpectedTargetIdentity,\n\t\t);\n\t},\n\tcreatePlanner(loaded) {\n\t\tconst registry = createPackRegistry([\n\t\t\tcreatePgTransitionPack({\n\t\t\t\t...(loaded.dbCasing ? { dbCasing: loaded.dbCasing } : {}),\n\t\t\t}),\n\t\t]);\n\t\tconst comparator = createComparator(registry);\n\t\tconst prover = createProver(registry);\n\t\treturn {\n\t\t\tcompare: (desired, current, context) =>\n\t\t\t\tcomparator.compare(desired, current, equivalenceContext(context)),\n\t\t\tprove: (compare, pool, context) =>\n\t\t\t\tprover.prove(compare, createPgTransitionLessor(pool), context),\n\t\t\trender: (plan, context) => renderProvenPlanSql(registry, plan, context),\n\t\t};\n\t},\n\tasync persist(pool, run, plan) {\n\t\tconst lease = await acquireTransitionLease(createPgTransitionLessor(pool));\n\t\ttry {\n\t\t\tawait createPgTransitionRunPersister(lease.session).persist(run, plan);\n\t\t} finally {\n\t\t\tawait lease.release();\n\t\t}\n\t},\n\tbuildExecutionContract: buildPgExecutionContract,\n};\n\nfunction resolvedDeps(overrides?: Partial<PlanDeps>): PlanDeps {\n\treturn { ...defaultPlanDeps, ...overrides };\n}\n\nfunction describeThrown(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction executionContractBlockedAssessment(\n\terror: PgExecutionContractDerivationError,\n): PlanAssessment {\n\treturn {\n\t\tdecision: 'blocked',\n\t\tassurance: 'unproven',\n\t\tlifecycle: 'planned',\n\t\tcontinuation: 'replan-required',\n\t\treasons: [\n\t\t\t{\n\t\t\t\tcode: 'unsupported-transition',\n\t\t\t\tchanges: [],\n\t\t\t\tscope: [],\n\t\t\t\tdetail: error.message,\n\t\t\t},\n\t\t],\n\t};\n}\n\n/** Render only a complete proven plan. This is an inspection view, never apply input. */\nexport function renderProvenPlanSql(\n\tregistry: PackRegistry,\n\tplan: InProcessProvenPlan,\n\tcontext: ObservationContext,\n): string {\n\tconst statements = plan.steps.map((step) => {\n\t\tconst resolution = registry.resolveOperation(step.operation);\n\t\tif (!resolution.ok || !resolution.semantics.renderPlanSql) {\n\t\t\tthrow new Error(\n\t\t\t\t`no SQL renderer is registered for proven operation ${step.operation.operationKind.name}`,\n\t\t\t);\n\t\t}\n\t\treturn resolution.semantics.renderPlanSql(step.operation, context);\n\t});\n\treturn [\n\t\t'-- dbsp transition plan view; apply accepts a persisted run id, never this SQL.',\n\t\t...statements.map((statement) => `${statement};`),\n\t].join('\\n');\n}\n\nexport async function runPlan(\n\toptions: PlanOptions,\n\toverrides?: Partial<PlanDeps>,\n): Promise<PlanResult> {\n\tconst deps = resolvedDeps(overrides);\n\tconst format = options.format ?? 'sql';\n\tif (format !== 'sql' && format !== 'json') {\n\t\tthrow new Error(`unsupported plan format ${format}; expected sql or json`);\n\t}\n\tconst loaded = await deps.loadSchema(options.schemaFile);\n\tconst connection = await deps.createDbConnection(options.db);\n\tconst { pool } = connection;\n\tlet result: PlanResult | undefined;\n\tlet operationError: unknown;\n\tlet failed = false;\n\ttry {\n\t\t// This binding is deliberately first: every subsequent introspection and\n\t\t// proof lease must describe the same physical PostgreSQL target.\n\t\tconst targetIdentity = await deps.captureTargetIdentity(\n\t\t\tpool,\n\t\t\toptions.schema,\n\t\t);\n\t\tawait deps.ensureTransitionJournal(pool);\n\t\tconst current = await deps.loadCurrent(\n\t\t\tpool,\n\t\t\toptions.schema,\n\t\t\ttargetIdentity,\n\t\t);\n\t\tconst context = await deps.readContext(\n\t\t\tpool,\n\t\t\toptions.schema,\n\t\t\ttargetIdentity,\n\t\t);\n\t\tconst planner = deps.createPlanner(loaded);\n\t\tconst compare = planner.compare(loaded.model, current, context);\n\t\tconst prove = await planner.prove(compare, pool, context);\n\n\t\tif (prove.kind === 'proven') {\n\t\t\tlet executionContract: ExecutionContract | undefined;\n\t\t\ttry {\n\t\t\t\texecutionContract = await deps.buildExecutionContract(\n\t\t\t\t\tpool,\n\t\t\t\t\toptions.schema,\n\t\t\t\t\tprove.plan,\n\t\t\t\t\ttargetIdentity,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tif (!(error instanceof PgExecutionContractDerivationError)) throw error;\n\t\t\t\tresult = {\n\t\t\t\t\tcompareKind: compare.kind,\n\t\t\t\t\tproveKind: 'blocked',\n\t\t\t\t\tassessment: executionContractBlockedAssessment(error),\n\t\t\t\t\tpersisted: false,\n\t\t\t\t\trunId: null,\n\t\t\t\t\tplanDigest: null,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (executionContract !== undefined) {\n\t\t\t\t// Order is intentional: an id exists before an indeterminate write, while\n\t\t\t\t// rendering happens before a durable record can be stranded unseen.\n\t\t\t\tconst durablePlan = bindExecutionContract(\n\t\t\t\t\tprove.plan,\n\t\t\t\t\texecutionContract,\n\t\t\t\t);\n\t\t\t\tconst run = createTransitionRunMetadata(durablePlan);\n\t\t\t\tconst proofContext = prove.plan.observations.find(\n\t\t\t\t\t(observation) => observation.role === 'evidence',\n\t\t\t\t)?.context;\n\t\t\t\tif (!proofContext) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'internal error: minted proven plan has no evidence observation context',\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst sql = planner.render(durablePlan, proofContext);\n\t\t\t\tif (!options.dryRun) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait deps.persist(pool, run, durablePlan);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthrow new PlanPersistenceIndeterminateError(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcompareKind: compare.kind,\n\t\t\t\t\t\t\t\tproveKind: prove.kind,\n\t\t\t\t\t\t\t\tassessment: prove.assessment,\n\t\t\t\t\t\t\t\tpersisted: 'indeterminate',\n\t\t\t\t\t\t\t\trunId: run.runId,\n\t\t\t\t\t\t\t\tplanDigest: run.planDigest,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tresult = {\n\t\t\t\t\tcompareKind: compare.kind,\n\t\t\t\t\tproveKind: prove.kind,\n\t\t\t\t\tassessment: prove.assessment,\n\t\t\t\t\tpersisted: !options.dryRun,\n\t\t\t\t\trunId: options.dryRun ? null : run.runId,\n\t\t\t\t\tplanDigest: run.planDigest,\n\t\t\t\t\tplan: durablePlan,\n\t\t\t\t\tsql,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif (prove.kind === 'no-drift') {\n\t\t\tresult = {\n\t\t\t\tcompareKind: compare.kind,\n\t\t\t\tproveKind: prove.kind,\n\t\t\t\tassessment: prove.assessment,\n\t\t\t\tpersisted: false,\n\t\t\t\trunId: null,\n\t\t\t\tplanDigest: null,\n\t\t\t};\n\t\t} else if (prove.kind !== 'proven') {\n\t\t\tresult = {\n\t\t\t\tcompareKind: compare.kind,\n\t\t\t\tproveKind: prove.kind,\n\t\t\t\tassessment: prove.assessment,\n\t\t\t\tpersisted: false,\n\t\t\t\trunId: null,\n\t\t\t\tplanDigest: null,\n\t\t\t};\n\t\t}\n\t} catch (error) {\n\t\tfailed = true;\n\t\toperationError = error;\n\t}\n\n\tlet cleanup: CleanupFailure = noCleanupFailure;\n\ttry {\n\t\tawait connection.release();\n\t} catch (error) {\n\t\tcleanup = { kind: 'failed', error };\n\t}\n\n\tif (failed) {\n\t\tif (operationError instanceof PlanPersistenceIndeterminateError) {\n\t\t\tthrow new PlanPersistenceIndeterminateError(\n\t\t\t\toperationError.result,\n\t\t\t\toperationError.persistenceError,\n\t\t\t\tcleanup,\n\t\t\t);\n\t\t}\n\t\tif (cleanup.kind === 'failed') {\n\t\t\tthrow new PlanOperationAndCleanupError(operationError, cleanup.error);\n\t\t}\n\t\tthrow operationError;\n\t}\n\tif (cleanup.kind === 'failed') {\n\t\tthrow new PlanCleanupError(result as PlanResult, cleanup.error);\n\t}\n\treturn result as PlanResult;\n}\n\nexport function formatPlanJson(result: PlanResult, dryRun: boolean) {\n\treturn {\n\t\tcompareKind: result.compareKind,\n\t\tproveKind: result.proveKind,\n\t\tassessment: result.assessment,\n\t\tpersisted: result.persisted,\n\t\trunId: result.runId,\n\t\tplanDigest: result.planDigest,\n\t\t...(result.plan ? { plan: result.plan } : {}),\n\t\t...(result.sql ? { sql: result.sql } : {}),\n\t\t...(dryRun && result.proveKind === 'proven'\n\t\t\t? { preview: 'non-executable; no durable dbsp record' }\n\t\t\t: {}),\n\t};\n}\n\nexport function formatPlanHuman(result: PlanResult, dryRun: boolean): string {\n\tif (result.proveKind === 'proven') {\n\t\treturn [\n\t\t\tdryRun\n\t\t\t\t? 'Proven transition preview (non-executable; no durable dbsp record):'\n\t\t\t\t: 'Proven transition plan:',\n\t\t\t// Every operation renderer converges on result.sql before this human-only\n\t\t\t// view, so database-sourced SQL cannot bypass terminal escaping here.\n\t\t\t...(result.sql === undefined ? [] : [escapeDiagnosticText(result.sql)]),\n\t\t\t...(result.plan?.executionContract\n\t\t\t\t? [\n\t\t\t\t\t\t'Execution contract:',\n\t\t\t\t\t\t...result.plan.executionContract.requirements.map(\n\t\t\t\t\t\t\t(requirement) =>\n\t\t\t\t\t\t\t\t` ${escapeDiagnosticText(JSON.stringify(requirement))}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t]\n\t\t\t\t: []),\n\t\t\tdryRun\n\t\t\t\t? `Preview digest: ${result.planDigest}`\n\t\t\t\t: `Run id: ${result.runId}\\nPlan digest: ${result.planDigest}`,\n\t\t]\n\t\t\t.filter((line): line is string => line !== undefined)\n\t\t\t.join('\\n');\n\t}\n\tif (result.proveKind === 'no-drift') {\n\t\treturn 'Database already matches the target; nothing was persisted.';\n\t}\n\treturn `No durable plan was created.\\n${escapeDiagnosticText(JSON.stringify(result.assessment, null, 2))}`;\n}\n\nfunction preservedPlanResult(\n\terror: unknown,\n\tfallback?: PlanResult,\n): PlanResult | undefined {\n\tif (error instanceof PlanPersistenceIndeterminateError) return error.result;\n\tif (error instanceof PlanCleanupError) return error.result;\n\treturn fallback;\n}\n\nfunction primaryPlanError(error: unknown): unknown {\n\tif (error instanceof PlanPersistenceIndeterminateError) {\n\t\treturn error.persistenceError;\n\t}\n\tif (error instanceof PlanCleanupError) return error.cleanupError;\n\tif (error instanceof PlanOperationAndCleanupError) {\n\t\treturn error.operationError;\n\t}\n\treturn error;\n}\n\nfunction cleanupFailure(error: unknown): CleanupFailure {\n\tif (error instanceof PlanPersistenceIndeterminateError) {\n\t\treturn error.cleanup;\n\t}\n\tif (error instanceof PlanCleanupError) {\n\t\treturn { kind: 'failed', error: error.cleanupError };\n\t}\n\tif (error instanceof PlanOperationAndCleanupError) {\n\t\treturn { kind: 'failed', error: error.cleanupError };\n\t}\n\treturn noCleanupFailure;\n}\n\n/** The stable error contract for both planning and post-outcome failures. */\nexport function formatPlanFailureJson(error: unknown, fallback?: PlanResult) {\n\tconst result = preservedPlanResult(error, fallback);\n\tconst cleanupError = cleanupFailure(error);\n\treturn {\n\t\tcompareKind: result?.compareKind ?? null,\n\t\tproveKind: result?.proveKind ?? null,\n\t\tassessment: result?.assessment ?? null,\n\t\tpersisted: result?.persisted ?? false,\n\t\trunId: result?.runId ?? null,\n\t\tplanDigest: result?.planDigest ?? null,\n\t\terror: describeThrown(primaryPlanError(error)),\n\t\t...(cleanupError.kind === 'not-failed'\n\t\t\t? {}\n\t\t\t: { cleanupError: describeThrown(cleanupError.error) }),\n\t};\n}\n\nfunction formatPlanFailureHuman(error: unknown, fallback?: PlanResult): string {\n\tconst result = preservedPlanResult(error, fallback);\n\tconst fields = result\n\t\t? [\n\t\t\t\tresult.persisted === true\n\t\t\t\t\t? 'A durable plan was created before this failure.'\n\t\t\t\t\t: result.persisted === 'indeterminate'\n\t\t\t\t\t\t? 'Persistence is indeterminate; inspect the minted run before retrying.'\n\t\t\t\t\t\t: 'No durable plan was created.',\n\t\t\t\t...(result.runId ? [`Run id: ${result.runId}`] : []),\n\t\t\t\t...(result.planDigest ? [`Plan digest: ${result.planDigest}`] : []),\n\t\t\t]\n\t\t: [];\n\tconst cleanupError = cleanupFailure(error);\n\treturn [\n\t\t`ā ${escapeDiagnosticText(describeThrown(primaryPlanError(error)))}`,\n\t\t...fields,\n\t\t...(cleanupError.kind === 'not-failed'\n\t\t\t? []\n\t\t\t: [\n\t\t\t\t\t`Connection release also failed: ${escapeDiagnosticText(describeThrown(cleanupError.error))}`,\n\t\t\t\t]),\n\t].join('\\n');\n}\n\nfunction printHumanResult(result: PlanResult, dryRun: boolean): void {\n\tconsole.log(formatPlanHuman(result, dryRun));\n}\n\nexport function exitCodeForPlanResult(result: PlanResult): 0 | 1 {\n\treturn result.proveKind === 'blocked' || result.proveKind === 'inapplicable'\n\t\t? 1\n\t\t: 0;\n}\n\nexport const planCommand = new Command('plan')\n\t.description('Prove and persist a transition plan without applying it')\n\t.argument('<schema-file>', 'Schema DSL file')\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--schema <name>', 'Database schema name', 'public')\n\t.option('--dry-run', 'Prove and render without persisting a transition run')\n\t.option('--format <format>', 'Output format: sql or json', 'sql')\n\t.exitOverride()\n\t// The root handler owns parse-error presentation. Suppress Commander's\n\t// eager stderr write so --format json remains a single JSON document.\n\t.configureOutput({ writeErr: () => {} })\n\t.action(\n\t\tasync (\n\t\t\tschemaFile: string,\n\t\t\toptions: {\n\t\t\t\tdb: string;\n\t\t\t\tschema?: string;\n\t\t\t\tdryRun?: boolean;\n\t\t\t\tformat?: PlanFormat;\n\t\t\t},\n\t\t) => {\n\t\t\tlet result: PlanResult | undefined;\n\t\t\ttry {\n\t\t\t\tresult = await runPlan({ ...options, schemaFile });\n\t\t\t\tif (options.format === 'json') {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\tformatPlanJson(result, options.dryRun === true),\n\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tprintHumanResult(result, options.dryRun === true);\n\t\t\t\t}\n\t\t\t\tprocess.exitCode = exitCodeForPlanResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tif (options.format === 'json') {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\tJSON.stringify(formatPlanFailureJson(error, result), null, 2),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(formatPlanFailureHuman(error, result));\n\t\t\t\t}\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t}\n\t\t},\n\t);\n","/**\n * Push Command ā Schema Provisioning\n *\n * dbsp push - Push schema to database.\n * Additive by default: only creates missing objects.\n * With --drop: recreates from scratch (preserves _dbsp_migrations).\n */\n\nimport type {\n\tExpressionCanonicalizationWarning,\n\tSchemaChange,\n\tSchemaDiff,\n} from '@dbsp/adapter-pgsql';\nimport {\n\tcomparePgsqlDatabaseSchema,\n\tcreatePgsqlAdapter,\n\tescapeDiagnosticText,\n\tgenerateDDL,\n\tgenerateMigrationSQL,\n\tgetNamingPluginForDbCasing,\n} from '@dbsp/adapter-pgsql';\nimport { Command } from 'commander';\nimport { executeDdl } from '../ddl-executor.js';\nimport { createDbConnection, redactDbUrl } from '../utils/db-utils.js';\nimport { loadSchema } from '../utils/schema-loader.js';\n\n/** Table name reserved for migration history ā never dropped by push. */\nconst MIGRATIONS_TABLE = '_dbsp_migrations';\n\nexport const pushCommand = new Command('push')\n\t.description('Push schema to database (additive by default)')\n\t.option(\n\t\t'-s, --schema <path>',\n\t\t'Path to schema file (default: dbsp.schema.ts)',\n\t)\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--schema-name <name>', 'Database schema name (default: public)')\n\t.option('--drop', 'Drop and recreate all objects (preserves migrations)')\n\t.option('--dry-run', 'Print SQL without executing')\n\t.option('--json', 'Output as JSON')\n\t.action(\n\t\tasync (options: {\n\t\t\tschema?: string;\n\t\t\tdb: string;\n\t\t\tschemaName?: string;\n\t\t\tdrop?: boolean;\n\t\t\tdryRun?: boolean;\n\t\t\tjson?: boolean;\n\t\t}) => {\n\t\t\tconst schemaPath = options.schema ?? 'dbsp.schema.ts';\n\t\t\tconst redactedUrl = redactDbUrl(options.db);\n\n\t\t\tif (!options.json) {\n\t\t\t\tconsole.log(\n\t\t\t\t\t`š Pushing schema: ${schemaPath}${options.drop ? ' (with --drop)' : ''}`,\n\t\t\t\t);\n\t\t\t\tconsole.log(` Database: ${redactedUrl}`);\n\t\t\t\tif (options.schemaName) {\n\t\t\t\t\tconsole.log(` Schema: ${options.schemaName}`);\n\t\t\t\t}\n\t\t\t\tif (options.dryRun) {\n\t\t\t\t\tconsole.log(` Mode: DRY RUN (no changes will be applied)`);\n\t\t\t\t}\n\t\t\t\tconsole.log('');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst loaded = await loadSchema(schemaPath);\n\t\t\t\tconst schemaModel = loaded.model;\n\n\t\t\t\tconst { pool } = await createDbConnection(options.db);\n\n\t\t\t\ttry {\n\t\t\t\t\tif (options.drop) {\n\t\t\t\t\t\t// --drop mode: generate full DDL with drops, excluding _dbsp_migrations\n\t\t\t\t\t\tconst statements = generateDDL(schemaModel, {\n\t\t\t\t\t\t\tincludeDropStatements: true,\n\t\t\t\t\t\t\t...(options.schemaName ? { schemaName: options.schemaName } : {}),\n\t\t\t\t\t\t\t...(loaded.dbCasing !== undefined\n\t\t\t\t\t\t\t\t? { naming: getNamingPluginForDbCasing(loaded.dbCasing) }\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst migrationsPattern =\n\t\t\t\t\t\t\tbuildMigrationsTableDropPattern(MIGRATIONS_TABLE);\n\t\t\t\t\t\tconst filtered = statements.filter(\n\t\t\t\t\t\t\t(stmt) => !migrationsPattern.test(stmt),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\toutputResult(filtered, options);\n\n\t\t\t\t\t\tconst result = await executeDdl(pool, filtered, {\n\t\t\t\t\t\t\t...(options.dryRun !== undefined\n\t\t\t\t\t\t\t\t? { dryRun: options.dryRun }\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (options.json) {\n\t\t\t\t\t\t\tconst droppedTables = statements\n\t\t\t\t\t\t\t\t.filter((s) => /DROP\\s+TABLE/i.test(s))\n\t\t\t\t\t\t\t\t.filter((s) => !migrationsPattern.test(s))\n\t\t\t\t\t\t\t\t.map(extractDroppedTableName)\n\t\t\t\t\t\t\t\t.filter((t): t is string => t !== undefined);\n\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tstatus: options.dryRun ? 'dry-run' : 'dropped',\n\t\t\t\t\t\t\t\t\t\ttables: droppedTables,\n\t\t\t\t\t\t\t\t\t\ttablesDropped: droppedTables.length,\n\t\t\t\t\t\t\t\t\t\tstatementsExecuted: result.statementsExecuted,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else if (!options.dryRun) {\n\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\t`\\nā
Push complete: ${result.statementsExecuted} statements executed`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Additive mode: live diff -> generate migration SQL (additive only)\n\t\t\t\t\t\tconst adapter = createPgsqlAdapter(pool);\n\t\t\t\t\t\tconst compareOptions = {\n\t\t\t\t\t\t\t...(options.schemaName ? { schema: options.schemaName } : {}),\n\t\t\t\t\t\t\t...(loaded.dbCasing ? { dbCasing: loaded.dbCasing } : {}),\n\t\t\t\t\t\t\tonExpressionCanonicalizationWarning: (\n\t\t\t\t\t\t\t\twarning: ExpressionCanonicalizationWarning,\n\t\t\t\t\t\t\t) =>\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`ā ļø [${warning.kind} ${escapeDiagnosticText(warning.table)}.${escapeDiagnosticText(warning.name)}] ${warning.message}`,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst diff = await comparePgsqlDatabaseSchema(\n\t\t\t\t\t\t\tadapter,\n\t\t\t\t\t\t\tschemaModel,\n\t\t\t\t\t\t\tcompareOptions,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// Generate SQL for additive changes only (no destructive)\n\t\t\t\t\t\tconst statements = generateMigrationSQL(diff, {\n\t\t\t\t\t\t\tincludeDestructive: false,\n\t\t\t\t\t\t\t...(options.schemaName ? { schemaName: options.schemaName } : {}),\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Collect warnings for skipped non-additive changes\n\t\t\t\t\t\tconst skippedChanges = diff.changes.filter((c) => c.destructive);\n\n\t\t\t\t\t\tif (!options.json && skippedChanges.length > 0) {\n\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\t`ā ļø ${skippedChanges.length} non-additive change(s) skipped:`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tfor (const change of skippedChanges) {\n\t\t\t\t\t\t\t\tconsole.log(` - ${change.details}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconsole.log('');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (statements.length === 0) {\n\t\t\t\t\t\t\tif (options.json) {\n\t\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tstatus: 'up-to-date',\n\t\t\t\t\t\t\t\t\t\t\tstatementsExecuted: 0,\n\t\t\t\t\t\t\t\t\t\t\tskippedChanges: skippedChanges.length,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconsole.log('ā
Database is up to date ā nothing to push.');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// EH-14: return instead of process.exit(0) so pool.end() in finally runs\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\toutputResult(statements, options);\n\n\t\t\t\t\t\tconst result = await executeDdl(pool, statements, {\n\t\t\t\t\t\t\t...(options.dryRun !== undefined\n\t\t\t\t\t\t\t\t? { dryRun: options.dryRun }\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (!options.dryRun) {\n\t\t\t\t\t\t\tconst postApplyDiff = await comparePgsqlDatabaseSchema(\n\t\t\t\t\t\t\t\tadapter,\n\t\t\t\t\t\t\t\tschemaModel,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t...compareOptions,\n\t\t\t\t\t\t\t\t\tpreviouslyAppliedDiff: diff,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tassertNoUnexpectedResidualDrift(postApplyDiff, skippedChanges);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (options.json) {\n\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tstatus: options.dryRun ? 'dry-run' : 'applied',\n\t\t\t\t\t\t\t\t\t\tstatementsExecuted: result.statementsExecuted,\n\t\t\t\t\t\t\t\t\t\tskippedChanges: skippedChanges.length,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else if (!options.dryRun) {\n\t\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\t\t`\\nā
Push complete: ${result.statementsExecuted} statement(s) executed`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// EH-14: return so finally runs pool.end() before the outer success path\n\t\t\t\t} finally {\n\t\t\t\t\tawait pool.end();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst message =\n\t\t\t\t\terror instanceof Error ? error.message : 'Unknown error occurred';\n\t\t\t\t// CC-2+EH-7: If --json, error goes to stdout as JSON; otherwise stderr\n\t\t\t\tif (options.json) {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\tJSON.stringify({ status: 'error', error: message }, null, 2),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(`ā Error: ${message}`);\n\t\t\t\t}\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n\n/**\n * Output SQL statements (dry-run or --json mode).\n */\n/**\n * Match a `DROP TABLE` statement that targets the migrations table, so `--drop`\n * can never destroy dbsp's own migration history.\n *\n * The table name is escaped before it reaches the pattern: an unescaped `.` or\n * `$` in it would otherwise match characters it should not, and a table whose\n * name merely resembles the migrations table would be spared ā or worse, one\n * that should be spared would be dropped.\n *\n * The pattern matches the quoted name anywhere in the statement rather than\n * anchoring to the end. That is safe because `generateDDL` returns one statement\n * per array entry, so a match can never jump across a statement boundary.\n */\nexport function buildMigrationsTableDropPattern(tableName: string): RegExp {\n\tconst escaped = tableName.replace(/[.*+?^${}()|[\\]\\\\]/gu, '\\\\$&');\n\treturn new RegExp(\n\t\t`DROP\\\\s+TABLE(?:\\\\s+IF\\\\s+EXISTS)?(?:\\\\s+\"[^\"]*\"\\\\s*\\\\.)?\\\\s*\"${escaped}\"`,\n\t\t'i',\n\t);\n}\n\n/**\n * Read the table name out of a `DROP TABLE` statement for the JSON report.\n *\n * The name is the last quoted identifier, which skips the schema in\n * `\"public\".\"users\"`, and it may be followed by `CASCADE` before the semicolon.\n * Returns the statement itself when nothing matches, so the report never silently\n * loses a table.\n */\nexport function extractDroppedTableName(statement: string): string {\n\tconst match = statement.match(/\"([^\"]+)\"\\s*(?:CASCADE\\s*)?;?\\s*$/iu);\n\treturn match?.[1] ?? statement;\n}\n\nfunction outputResult(\n\tstatements: readonly string[],\n\toptions: { dryRun?: boolean; json?: boolean },\n): void {\n\tif (options.dryRun && !options.json) {\n\t\tconsole.log(`-- Dry run: ${statements.length} statement(s)\\n`);\n\t\tfor (const stmt of statements) {\n\t\t\tconsole.log(`${stmt};\\n`);\n\t\t}\n\t}\n}\n\nfunction assertNoUnexpectedResidualDrift(\n\tpostApplyDiff: SchemaDiff,\n\tskippedChanges: readonly SchemaChange[],\n): void {\n\tconst skippedKeys = new Set(skippedChanges.map(changeIdentity));\n\tconst unexpected = postApplyDiff.changes.filter(\n\t\t(change) =>\n\t\t\t!(change.destructive && skippedKeys.has(changeIdentity(change))),\n\t);\n\tif (unexpected.length === 0) return;\n\n\tthrow new Error(\n\t\t`Push did not converge after applying DDL; ${unexpected.length} outstanding change(s) remain:\\n` +\n\t\t\tunexpected.map(formatOutstandingChange).join('\\n'),\n\t);\n}\n\nfunction changeIdentity(change: SchemaChange): string {\n\treturn JSON.stringify([\n\t\tchange.kind,\n\t\tchange.table,\n\t\tchange.column ?? null,\n\t\tchange.details,\n\t\tchange.destructive,\n\t]);\n}\n\nfunction formatOutstandingChange(change: SchemaChange): string {\n\tconst target = change.column\n\t\t? `${change.table}.${change.column}`\n\t\t: change.table || 'schema';\n\treturn ` - ${change.details} (${change.kind}: ${target})`;\n}\n","/**\n * DDL Executor ā Transaction-wrapped DDL execution.\n *\n * Shared by `dbsp push` and `dbsp migrate apply`.\n * Executes an array of SQL statements inside a single transaction.\n */\n\nimport type { Pool, PoolClient } from 'pg';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DdlExecutionResult {\n\t/** Number of statements executed */\n\tstatementsExecuted: number;\n\t/** Whether execution was a dry-run (no actual changes) */\n\tdryRun: boolean;\n}\n\n// ============================================================================\n// Executor\n// ============================================================================\n\n/**\n * Execute DDL statements in a transaction.\n *\n * @param pool - pg Pool instance\n * @param statements - SQL statements to execute\n * @param options - Execution options\n * @returns Execution result\n */\nexport async function executeDdl(\n\tpool: Pool,\n\tstatements: readonly string[],\n\toptions?: { dryRun?: boolean },\n): Promise<DdlExecutionResult> {\n\tif (statements.length === 0) {\n\t\treturn { statementsExecuted: 0, dryRun: options?.dryRun ?? false };\n\t}\n\n\tif (options?.dryRun) {\n\t\treturn { statementsExecuted: statements.length, dryRun: true };\n\t}\n\n\tlet client: PoolClient | undefined;\n\ttry {\n\t\tclient = await pool.connect();\n\t\tawait client.query('BEGIN');\n\n\t\tfor (const stmt of statements) {\n\t\t\tawait client.query(stmt);\n\t\t}\n\n\t\tawait client.query('COMMIT');\n\t\treturn { statementsExecuted: statements.length, dryRun: false };\n\t} catch (error) {\n\t\tif (client) {\n\t\t\tawait client.query('ROLLBACK');\n\t\t}\n\t\tthrow error;\n\t} finally {\n\t\tif (client) {\n\t\t\tclient.release();\n\t\t}\n\t}\n}\n","/**\n * DX-030 Block 1: REPL Command\n *\n * dbsp repl [--schema <path>] - Launch interactive REPL.\n * CLI-022: Batch mode support with --eval and --input options.\n */\n\nimport { readFileSync } from 'node:fs';\nimport type { DbCasing } from '@dbsp/types';\nimport { Command } from 'commander';\nimport { config } from '../config.js';\nimport { validateIdentifier } from '../utils/identifier-validation.js';\nimport { loadSchema, loadSchemaFromCwd } from '../utils/schema-loader.js';\n\nexport interface ReplOptions {\n\tschema?: string;\n\t/** CLI-020: Database connection URL for execution mode */\n\tdb?: string;\n\t/** CLI-022: Single query to evaluate (batch mode) */\n\teval?: string;\n\t/** CLI-022: File containing queries to execute (batch mode, one per line) */\n\tinput?: string;\n\t/** CLI-022: Output format for batch mode */\n\tformat?: 'text' | 'json';\n\t/** DEMO-E2E: Assertion file for validating query output */\n\tassert?: string;\n\t/** CLI-IMPORT: SQL files to import before queries (injected as .import commands) */\n\timport?: string[];\n\t/** CLI-USE: PostgreSQL schema to use (injected as .use command) */\n\tuse?: string;\n\t/** CLI-MUT: Start REPL with parse mode enabled */\n\tparse?: boolean;\n\t/** CLI-MUT: Start REPL with exec mode enabled */\n\texec?: boolean;\n\t/** CLI-CONFIG: Custom config file path (default: ~/.dbsp/config.json) */\n\tconfig?: string;\n\t/** CLI-CASING: Column naming convention (describes DB column casing) */\n\tcasing?: 'snake' | 'camel' | 'none';\n}\n\nexport const replCommand = new Command('repl')\n\t.description('Launch interactive REPL for exploring schema and queries')\n\t.option('-s, --schema <path>', 'Path to schema file (default: auto-detect)')\n\t.option(\n\t\t'-d, --db <url>',\n\t\t'PostgreSQL connection URL for execution mode (e.g., postgres://localhost/mydb)',\n\t)\n\t.option('-e, --eval <query>', 'Execute a single query and exit (batch mode)')\n\t.option(\n\t\t'-i, --input <file>',\n\t\t'Execute queries from file, one per line (batch mode)',\n\t)\n\t.option(\n\t\t'-f, --format <format>',\n\t\t'Output format for batch mode: text (default) or json',\n\t\t'text',\n\t)\n\t.option(\n\t\t'-a, --assert <file>',\n\t\t'Assertion file to validate query output (requires --input)',\n\t)\n\t.option(\n\t\t'--import <files...>',\n\t\t'SQL files to import before queries (equivalent to .import commands)',\n\t)\n\t.option(\n\t\t'--use <schema>',\n\t\t'PostgreSQL schema to use (equivalent to .use command)',\n\t)\n\t.option('--parse', 'Start REPL with parse mode enabled (.parse toggle)')\n\t.option('--exec', 'Start REPL with exec mode enabled (.exec toggle)')\n\t.option(\n\t\t'--casing <type>',\n\t\t'Column naming convention: snake (DB uses snake_case), camel (DB uses camelCase), none (preserve as-is)',\n\t)\n\t.option(\n\t\t'-c, --config <path>',\n\t\t'Custom config file path (default: ~/.dbsp/config.json)',\n\t)\n\t.action(async (options: ReplOptions) => {\n\t\t// Set custom config path if provided\n\t\tif (options.config) {\n\t\t\tconfig.setConfigPath(options.config);\n\t\t}\n\t\t// Load config\n\t\tconfig.load();\n\t\ttry {\n\t\t\t// Load schema\n\t\t\tlet schemaPath: string;\n\t\t\tlet schema: Awaited<ReturnType<typeof loadSchema>>;\n\n\t\t\tif (options.schema) {\n\t\t\t\tschema = await loadSchema(options.schema);\n\t\t\t\tschemaPath = options.schema;\n\t\t\t} else {\n\t\t\t\tconst result = await loadSchemaFromCwd();\n\t\t\t\tschema = result.schema;\n\t\t\t\tschemaPath = result.path;\n\t\t\t}\n\n\t\t\t// DEMO-E2E: Validate --assert requires --input\n\t\t\tif (options.assert && !options.input) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'--assert requires --input (assertion files validate query output from input files)',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// CLI-IMPORT: Validate that --import requires batch mode (SQL file execution)\n\t\t\t// Note: --use, --parse, --exec work in interactive mode (REPL state setup)\n\t\t\tif (options.import && !options.eval && !options.input) {\n\t\t\t\tthrow new Error('--import requires batch mode (--eval or --input)');\n\t\t\t}\n\n\t\t\t// SEC: Validate --use schema name at the entry point so both the batch path\n\t\t\t// (which injects `.use <schema>`) and the interactive path (which passes\n\t\t\t// initialSchemaName) are protected against SQL injection.\n\t\t\tif (options.use) {\n\t\t\t\tvalidateIdentifier(options.use, 'schema');\n\t\t\t}\n\n\t\t\t// CLI-CASING: explicit flag wins; otherwise use the schema declaration.\n\t\t\tconst dbCasing = mapReplCasingOption(options.casing) ?? schema.dbCasing;\n\n\t\t\t// CLI-022: Batch mode - execute queries without interactive UI\n\t\t\tif (options.eval || options.input) {\n\t\t\t\tconst { runBatchMode } = await import('../repl/batch.js');\n\t\t\t\tconst queries: string[] = [];\n\n\t\t\t\t// CLI-USE: Inject .use command first (schema scoping)\n\t\t\t\tif (options.use) {\n\t\t\t\t\tqueries.push(`.use ${options.use}`);\n\t\t\t\t}\n\n\t\t\t\t// CLI-IMPORT: Inject .import commands for SQL files\n\t\t\t\tif (options.import) {\n\t\t\t\t\tfor (const file of options.import) {\n\t\t\t\t\t\tqueries.push(`.import ${file}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (options.eval) {\n\t\t\t\t\tqueries.push(options.eval);\n\t\t\t\t}\n\n\t\t\t\tif (options.input) {\n\t\t\t\t\t// EH-2: Map ENOENT to a friendly error instead of raw stack trace\n\t\t\t\t\tlet content: string;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcontent = readFileSync(options.input, 'utf-8');\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconst isNotFound =\n\t\t\t\t\t\t\terr instanceof Error &&\n\t\t\t\t\t\t\t'code' in err &&\n\t\t\t\t\t\t\t(err as NodeJS.ErrnoException).code === 'ENOENT';\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\tisNotFound\n\t\t\t\t\t\t\t\t? `Input file not found: ${options.input}`\n\t\t\t\t\t\t\t\t: `Failed to read input file: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tqueries.push(...content.split('\\n'));\n\t\t\t\t}\n\n\t\t\t\tawait runBatchMode({\n\t\t\t\t\tqueries,\n\t\t\t\t\tschema,\n\t\t\t\t\tschemaPath,\n\t\t\t\t\tformat: options.format ?? 'text',\n\t\t\t\t\t...(options.db && { databaseUrl: options.db }),\n\t\t\t\t\t...(options.assert && { assertFile: options.assert }),\n\t\t\t\t\t...(dbCasing && { dbCasing }),\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Dynamic import to avoid loading React/Ink for other commands\n\t\t\tconst { startRepl } = await import('../repl/index.js');\n\t\t\t// CLI-020: Pass database URL if provided\n\t\t\t// CLI-MUT: Pass initial REPL state options\n\t\t\tawait startRepl({\n\t\t\t\tschema,\n\t\t\t\tschemaPath,\n\t\t\t\t...(options.db && { databaseUrl: options.db }),\n\t\t\t\t...(options.use && { initialSchemaName: options.use }),\n\t\t\t\t...(options.parse && { initialParseMode: true }),\n\t\t\t\t...(options.exec && { initialExecMode: true }),\n\t\t\t\t...(dbCasing && { dbCasing }),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconsole.error(`ā ${message}`);\n\t\t\tprocess.exit(1);\n\t\t}\n\t});\n\nfunction mapReplCasingOption(\n\tcasing: ReplOptions['casing'],\n): DbCasing | undefined {\n\tswitch (casing) {\n\t\tcase 'snake':\n\t\t\treturn 'snake_case';\n\t\tcase 'camel':\n\t\t\treturn 'camelCase';\n\t\tcase 'none':\n\t\t\treturn 'preserve';\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n","/**\n * Verify Command ā Schema Drift Detection\n *\n * dbsp verify - Compare schema vs real database using the comparison engine.\n * Detects drift in tables, columns, types, nullable, defaults, FKs, indexes.\n */\n\nimport {\n\tcomparePgsqlDatabaseSchema,\n\tcreatePgsqlAdapter,\n\tescapeDiagnosticText,\n} from '@dbsp/adapter-pgsql';\nimport { Command } from 'commander';\nimport { createDbConnection, redactDbUrl } from '../utils/db-utils.js';\nimport { loadSchema } from '../utils/schema-loader.js';\nimport { formatVerifyResult, verifyFromDiff } from '../verifier.js';\n\nexport const verifyCommand = new Command('verify')\n\t.description('Compare schema vs real database (drift detection)')\n\t.option(\n\t\t'-s, --schema <path>',\n\t\t'Path to schema file (default: dbsp.schema.ts)',\n\t)\n\t.requiredOption('-d, --db <url>', 'Database connection URL (required)')\n\t.option('--schema-name <name>', 'Database schema name (default: public)')\n\t.option('--json', 'Output as JSON')\n\t.action(\n\t\tasync (options: {\n\t\t\tschema?: string;\n\t\t\tdb: string;\n\t\t\tschemaName?: string;\n\t\t\tjson?: boolean;\n\t\t}) => {\n\t\t\tconst schemaPath = options.schema ?? 'dbsp.schema.ts';\n\n\t\t\tconst redactedUrl = redactDbUrl(options.db);\n\n\t\t\tif (!options.json) {\n\t\t\t\tconsole.log(`š Verifying schema: ${schemaPath}`);\n\t\t\t\tconsole.log(` Database: ${redactedUrl}`);\n\t\t\t\tif (options.schemaName) {\n\t\t\t\t\tconsole.log(` Schema: ${options.schemaName}`);\n\t\t\t\t}\n\t\t\t\tconsole.log('');\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// Load schema from file ā ModelIR\n\t\t\t\tconst loaded = await loadSchema(schemaPath);\n\t\t\t\tconst schemaModel = loaded.model;\n\n\t\t\t\t// Connect to database\n\t\t\t\tconst { pool } = await createDbConnection(options.db);\n\n\t\t\t\ttry {\n\t\t\t\t\tconst adapter = createPgsqlAdapter(pool);\n\t\t\t\t\t// Live diff: introspect database and canonicalise PostgreSQL CHECK\n\t\t\t\t\t// expressions before comparing.\n\t\t\t\t\tconst diff = await comparePgsqlDatabaseSchema(adapter, schemaModel, {\n\t\t\t\t\t\t...(options.schemaName ? { schema: options.schemaName } : {}),\n\t\t\t\t\t\t...(loaded.dbCasing !== undefined\n\t\t\t\t\t\t\t? { dbCasing: loaded.dbCasing }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\tonExpressionCanonicalizationWarning: (warning) =>\n\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t`ā ļø [${warning.kind} ${escapeDiagnosticText(warning.table)}.${escapeDiagnosticText(warning.name)}] ${warning.message}`,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t});\n\n\t\t\t\t\t// Convert to verify result\n\t\t\t\t\t// Keep the legacy reporting fields sourced from introspection so\n\t\t\t\t\t// --json consumers continue to see database table names as before.\n\t\t\t\t\tconst dbModel = await adapter.introspect({\n\t\t\t\t\t\t...(options.schemaName ? { schema: options.schemaName } : {}),\n\t\t\t\t\t});\n\t\t\t\t\tconst schemaTables = Array.from(schemaModel.tables.keys());\n\t\t\t\t\tconst dbTables = Array.from(dbModel.tables.keys());\n\t\t\t\t\tconst result = verifyFromDiff(diff, schemaTables, dbTables);\n\n\t\t\t\t\t// Output\n\t\t\t\t\tif (options.json) {\n\t\t\t\t\t\t// Exclude the full diff meta from JSON output (too verbose)\n\t\t\t\t\t\tconst { diff: _diff, ...jsonResult } = result;\n\t\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t\tJSON.stringify(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t...jsonResult,\n\t\t\t\t\t\t\t\t\tsummary: diff.summary,\n\t\t\t\t\t\t\t\t\thasDestructive: diff.hasDestructive,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconsole.log(formatVerifyResult(result));\n\t\t\t\t\t}\n\n\t\t\t\t\t// EH-14: set exit code; let finally run pool.end() before process exits\n\t\t\t\t\tprocess.exitCode = result.valid ? 0 : 1;\n\t\t\t\t\treturn;\n\t\t\t\t} finally {\n\t\t\t\t\t// Close database connection\n\t\t\t\t\tawait pool.end();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst message =\n\t\t\t\t\terror instanceof Error ? error.message : 'Unknown error occurred';\n\t\t\t\t// CC-2+EH-7: If --json, error goes to stdout as JSON; otherwise stderr\n\t\t\t\tif (options.json) {\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\tJSON.stringify({ status: 'error', error: message }, null, 2),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(`ā Error: ${message}`);\n\t\t\t\t}\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t},\n\t);\n","/**\n * Schema Verifier ā Drift Detection via Comparison Engine\n *\n * Compares schema definition against real database using the\n * adapter's compareSchemata engine for full drift detection.\n *\n * Detects: tables, columns, types, nullable, defaults, FKs, indexes, PKs.\n */\n\nimport type { ChangeKind, SchemaChange, SchemaDiff } from '@dbsp/adapter-pgsql';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type DriftSeverity = 'error' | 'warning' | 'info';\n\nexport type DriftType =\n\t// Tables\n\t| 'missing_table_in_db'\n\t| 'missing_table_in_schema'\n\t// Columns\n\t| 'missing_column_in_db'\n\t| 'missing_column_in_schema'\n\t| 'type_mismatch'\n\t| 'nullable_mismatch'\n\t| 'default_mismatch'\n\t| 'unique_mismatch'\n\t// Constraints\n\t| 'primary_key_mismatch'\n\t| 'missing_fk_in_db'\n\t| 'missing_fk_in_schema'\n\t| 'fk_on_delete_mismatch'\n\t// Indexes\n\t| 'missing_index_in_db'\n\t| 'missing_index_in_schema'\n\t// CHECK constraints\n\t| 'missing_check_in_db'\n\t| 'missing_check_in_schema'\n\t// ENUM types\n\t| 'missing_enum_in_db'\n\t| 'missing_enum_in_schema'\n\t| 'enum_value_mismatch'\n\t// Column enhancements\n\t| 'collation_mismatch'\n\t| 'identity_mismatch'\n\t// Comments\n\t| 'comment_mismatch'\n\t// Extensions & Sequences\n\t| 'missing_extension'\n\t| 'missing_sequence'\n\t| 'sequence_mismatch'\n\t// Constraints\n\t| 'constraint_validation_mismatch'\n\t// Row-Level Security\n\t| 'rls_enabled_mismatch'\n\t| 'missing_policy_in_db'\n\t| 'missing_policy_in_schema';\n\nexport interface DriftIssue {\n\t/** Issue severity */\n\tseverity: DriftSeverity;\n\t/** Human-readable message */\n\tmessage: string;\n\t/** Table affected (if any) */\n\ttable?: string;\n\t/** Column affected (if any) */\n\tcolumn?: string;\n\t/** Issue type for programmatic handling */\n\ttype: DriftType;\n}\n\nexport interface VerifyResult {\n\t/** Whether the schema matches the database */\n\tvalid: boolean;\n\t/** List of drift issues found */\n\tissues: DriftIssue[];\n\t/** Tables in schema */\n\tschemaTables: string[];\n\t/** Tables in database */\n\tdbTables: string[];\n\t/** Structured diff (for programmatic consumers) */\n\tdiff: SchemaDiff;\n}\n\n// ============================================================================\n// Change ā Drift Mapping\n// ============================================================================\n\nconst CHANGE_TO_DRIFT: Record<\n\tChangeKind,\n\t{ type: DriftType; severity: DriftSeverity }\n> = {\n\tcreate_table: { type: 'missing_table_in_db', severity: 'error' },\n\tdrop_table: { type: 'missing_table_in_schema', severity: 'warning' },\n\tadd_column: { type: 'missing_column_in_db', severity: 'error' },\n\tdrop_column: { type: 'missing_column_in_schema', severity: 'info' },\n\talter_column_type: { type: 'type_mismatch', severity: 'error' },\n\talter_column_nullable: { type: 'nullable_mismatch', severity: 'warning' },\n\talter_column_default: { type: 'default_mismatch', severity: 'warning' },\n\talter_column_unique: { type: 'unique_mismatch', severity: 'warning' },\n\tadd_primary_key: { type: 'primary_key_mismatch', severity: 'error' },\n\tdrop_primary_key: { type: 'primary_key_mismatch', severity: 'error' },\n\tadd_foreign_key: { type: 'missing_fk_in_db', severity: 'error' },\n\tdrop_foreign_key: { type: 'missing_fk_in_schema', severity: 'warning' },\n\talter_foreign_key: { type: 'fk_on_delete_mismatch', severity: 'warning' },\n\tcreate_index: { type: 'missing_index_in_db', severity: 'warning' },\n\tdrop_index: { type: 'missing_index_in_schema', severity: 'info' },\n\t// CHECK constraints\n\tadd_check_constraint: { type: 'missing_check_in_db', severity: 'warning' },\n\tdrop_check_constraint: { type: 'missing_check_in_schema', severity: 'info' },\n\t// ENUM types\n\tcreate_enum: { type: 'missing_enum_in_db', severity: 'error' },\n\talter_enum_add_value: { type: 'enum_value_mismatch', severity: 'warning' },\n\tdrop_enum: { type: 'missing_enum_in_schema', severity: 'warning' },\n\t// Column enhancements\n\talter_column_collation: { type: 'collation_mismatch', severity: 'warning' },\n\talter_column_identity: { type: 'identity_mismatch', severity: 'warning' },\n\t// Comments\n\tadd_comment: { type: 'comment_mismatch', severity: 'info' },\n\tdrop_comment: { type: 'comment_mismatch', severity: 'info' },\n\t// Extensions & Sequences\n\tcreate_extension: { type: 'missing_extension', severity: 'error' },\n\tdrop_extension: { type: 'missing_extension', severity: 'info' },\n\tcreate_sequence: { type: 'missing_sequence', severity: 'warning' },\n\talter_sequence: { type: 'sequence_mismatch', severity: 'warning' },\n\tdrop_sequence: { type: 'missing_sequence', severity: 'info' },\n\t// Constraints\n\tvalidate_constraint: {\n\t\ttype: 'constraint_validation_mismatch',\n\t\tseverity: 'warning',\n\t},\n\t// Row-Level Security\n\tenable_rls: { type: 'rls_enabled_mismatch', severity: 'warning' },\n\tdisable_rls: { type: 'rls_enabled_mismatch', severity: 'warning' },\n\tcreate_policy: { type: 'missing_policy_in_db', severity: 'warning' },\n\tdrop_policy: { type: 'missing_policy_in_schema', severity: 'warning' },\n};\n\nfunction changeToDriftIssue(change: SchemaChange): DriftIssue {\n\tconst mapping = CHANGE_TO_DRIFT[change.kind] ?? {\n\t\ttype: 'type_mismatch' as DriftType,\n\t\tseverity: 'warning' as DriftSeverity,\n\t};\n\treturn {\n\t\tseverity: mapping.severity,\n\t\ttype: mapping.type,\n\t\ttable: change.table,\n\t\t...(change.column !== undefined ? { column: change.column } : {}),\n\t\tmessage: change.details,\n\t};\n}\n\n// ============================================================================\n// Verification (from SchemaDiff)\n// ============================================================================\n\n/**\n * Convert a SchemaDiff into a VerifyResult.\n *\n * @param diff - Structured diff from compareSchemata()\n * @param schemaTables - Table names in schema (for backward compat)\n * @param dbTables - Table names in database (for backward compat)\n */\nexport function verifyFromDiff(\n\tdiff: SchemaDiff,\n\tschemaTables: string[],\n\tdbTables: string[],\n): VerifyResult {\n\tconst issues = diff.changes.map(changeToDriftIssue);\n\n\t// Sort by severity (error > warning > info)\n\tconst severityOrder: Record<DriftSeverity, number> = {\n\t\terror: 0,\n\t\twarning: 1,\n\t\tinfo: 2,\n\t};\n\tissues.sort(\n\t\t(a: DriftIssue, b: DriftIssue) =>\n\t\t\tseverityOrder[a.severity] - severityOrder[b.severity],\n\t);\n\n\tconst hasErrors = issues.some((i: DriftIssue) => i.severity === 'error');\n\n\treturn {\n\t\tvalid: !hasErrors,\n\t\tissues,\n\t\tschemaTables,\n\t\tdbTables,\n\t\tdiff,\n\t};\n}\n\n// ============================================================================\n// Format\n// ============================================================================\n\n/**\n * Format verification result for CLI output.\n */\nexport function formatVerifyResult(result: VerifyResult): string {\n\tconst lines: string[] = [];\n\n\tif (result.valid) {\n\t\tlines.push('ā
Schema matches database');\n\t} else {\n\t\tlines.push('ā Schema drift detected');\n\t}\n\n\tlines.push('');\n\tlines.push(`Tables in schema: ${result.schemaTables.length}`);\n\tlines.push(`Tables in database: ${result.dbTables.length}`);\n\tlines.push('');\n\n\tif (result.issues.length === 0) {\n\t\tlines.push('No issues found.');\n\t} else {\n\t\tconst errors = result.issues.filter((i) => i.severity === 'error');\n\t\tconst warnings = result.issues.filter((i) => i.severity === 'warning');\n\t\tconst infos = result.issues.filter((i) => i.severity === 'info');\n\n\t\tif (errors.length > 0) {\n\t\t\tlines.push(`ā ${errors.length} error(s):`);\n\t\t\tfor (const issue of errors) {\n\t\t\t\tlines.push(` ${issue.message}`);\n\t\t\t}\n\t\t\tlines.push('');\n\t\t}\n\n\t\tif (warnings.length > 0) {\n\t\t\tlines.push(`ā ļø ${warnings.length} warning(s):`);\n\t\t\tfor (const issue of warnings) {\n\t\t\t\tlines.push(` ${issue.message}`);\n\t\t\t}\n\t\t\tlines.push('');\n\t\t}\n\n\t\tif (infos.length > 0) {\n\t\t\tlines.push(`ā¹ļø ${infos.length} info:`);\n\t\t\tfor (const issue of infos) {\n\t\t\t\tlines.push(` ${issue.message}`);\n\t\t\t}\n\t\t\tlines.push('');\n\t\t}\n\t}\n\n\treturn lines.join('\\n');\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAOA,SAAS,WAAAA,UAAS,sBAAsB;;;ACQxC,SAAS,WAAW,qBAAqB;AACzC,SAAS,SAAS,eAAe;AAEjC,SAAS,eAAe;AAKjB,IAAM,kBAAkB,IAAI,QAAQ,UAAU,EACnD,YAAY,2BAA2B,EACvC,SAAS,YAAY,yBAAyB,EAC9C,OAAO,uBAAuB,4CAA4C,EAC1E,OAAO,mBAAmB,kDAAkD,EAC5E,OAAO,kBAAkB,oCAAoC,EAC7D,OAAO,UAAU,oDAAoD,EACrE,OAAO,wBAAwB,iCAAiC,EAChE;AAAA,EACA;AAAA,EACA;AACD,EACC;AAAA,EACA;AAAA,EACA;AACD,EACC;AAAA,EACA,OACC,QACA,YASI;AACJ,QAAI;AAIH,UAAI,WAAW,cAAc,WAAW,UAAU;AACjD,cAAM,IAAI;AAAA,UACT,WAAW,MAAM;AAAA,QAElB;AAAA,MACD;AACA,UAAI,WAAW,OAAO;AACrB,cAAM,IAAI,MAAM,mBAAmB,MAAM,0BAA0B;AAAA,MACpE;AAGA,UAAI;AACJ,UAAI;AAEJ,UAAI,QAAQ,QAAQ;AACnB,iBAAS,MAAM,WAAW,QAAQ,MAAM;AACxC,qBAAa,QAAQ;AAAA,MACtB,OAAO;AACN,cAAM,SAAS,MAAM,kBAAkB;AACvC,iBAAS,OAAO;AAChB,qBAAa,OAAO;AAAA,MACrB;AAGA,YAAM,aAAa,QAAQ,OAAO,QAAQ;AAC1C,YAAM,YAAY,WAAW,SAAS,CAAC;AACvC,YAAM,MAAM,YAAY,QAAQ,QAAQ,QAAQ;AAEhD,UAAI,iCAA0B,UAAU,EAAE;AAG1C,YAAM,UAAU,QAAQ,WAAW;AACnC,UAAI,CAAC,mBAAmB,OAAO,GAAG;AACjC,gBAAQ;AAAA,UACP;AAAA,QACD;AAAA,MACD;AAGA,cAAQ,QAAQ;AAAA,QACf,KAAK,OAAO;AAEX,gBAAM,WACL,oBAAoB,QAAQ,MAAM,KAClC,OAAO,YACN;AACF,gBAAM,cAAc,0BAA0B,QAAQ;AAGtD,gBAAM,EAAE,8BAA8B,IAAI,MAAM,OAC/C,qBACD;AAEA,gBAAM,UAAU,8BAA8B;AAAA,YAC7C;AAAA,YACA,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,UAChE,CAAC;AAED;AAEC,kBAAM,gBAAgB,QAAQ,YAAY,OAAO,OAAO;AAAA,cACvD,GAAI,QAAQ,SAAS,UAAa;AAAA,gBACjC,uBAAuB,QAAQ;AAAA,cAChC;AAAA,YACD,CAAC;AAED,kBAAM,aAAa,cAAc,KAAK,MAAM;AAC5C,kBAAMC,cAAa,QAAQ,OAAO,QAAQ;AAE1C,gBAAIA,aAAY;AAEf,oBAAM,UAAUA,YAAW,SAAS,MAAM,IACvC,QAAQ,QAAQ,IAAI,GAAGA,WAAU,IACjC,QAAQ,QAAQ,IAAI,GAAGA,aAAY,YAAY;AAElD,wBAAU,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/C,4BAAc,SAAS,YAAY,OAAO;AAE1C,sBAAQ,IAAI,yBAAoB,OAAO,EAAE;AACzC,sBAAQ,IAAI,cAAc,OAAO,WAAW,MAAM,EAAE;AACpD,sBAAQ,IAAI,kBAAkB,cAAc,MAAM,EAAE;AACpD,sBAAQ,IAAI,cAAc,WAAW,EAAE;AACvC,kBAAI,QAAQ,MAAM;AACjB,wBAAQ,IAAI,6BAA6B;AAAA,cAC1C;AACA,kBAAI,QAAQ,YAAY;AACvB,wBAAQ,IAAI,cAAc,QAAQ,UAAU,EAAE;AAAA,cAC/C;AAAA,YACD,OAAO;AAGN,sBAAQ,IAAI,UAAU;AAAA,YACvB;AAAA,UACD;AACA;AAAA,QACD;AAAA,MACD;AAAA,IACD,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,cAAQ,MAAM,UAAK,OAAO,EAAE;AAC5B,cAAQ,KAAK,CAAC;AAAA,IACf;AAAA,EACD;AACD;AAEM,SAAS,mBAAmB,SAA0C;AAC5E,SAAO,YAAY;AACpB;AAEO,SAAS,oBACf,QACuB;AACvB,UAAQ,QAAQ;AAAA,IACf,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR;AACC,aAAO;AAAA,EACT;AACD;AAEA,SAAS,0BACR,UAC6B;AAC7B,UAAQ,UAAU;AAAA,IACjB,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,EACT;AACD;;;ACzLA,SAAS,aAAAC,YAAW,iBAAAC,sBAAqB;AACzC,SAAS,WAAAC,UAAS,WAAAC,gBAAe;AACjC,SAAS,WAAAC,gBAAe;AAOxB,SAAS,eAAe,UAAuC;AAC9D,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SAAmB,CAAC;AAC1B,aAAW,WAAW,UAAU;AAC/B,QAAI,KAAK,IAAI,OAAO,EAAG;AACvB,SAAK,IAAI,OAAO;AAChB,WAAO,KAAK,OAAO;AAAA,EACpB;AACA,SAAO;AACR;AAEA,SAAS,eAAe,UAAmC;AAC1D,aAAW,WAAW,UAAU;AAC/B,YAAQ,IAAI,oBAAU,OAAO,EAAE;AAAA,EAChC;AACD;AAEO,IAAM,oBAAoB,IAAIC,SAAQ,YAAY,EACvD,YAAY,gDAAgD,EAC5D,eAAe,kBAAkB,oCAAoC,EACrE,OAAO,oBAAoB,sBAAsB,kBAAkB,EACnE,OAAO,wBAAwB,wBAAwB,QAAQ,EAC/D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,EACC,OAAO,wBAAwB,qCAAqC,EACpE,OAAO,yBAAyB,gCAAgC,EAChE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,EACC;AAAA,EACA,OAAO,YAQD;AACL,UAAM,cAAc,YAAY,QAAQ,EAAE;AAE1C,YAAQ,IAAI,qCAA8B,WAAW,EAAE;AACvD,YAAQ,IAAI,cAAc,QAAQ,UAAU,EAAE;AAC9C,QAAI,QAAQ,SAAS;AACpB,cAAQ,IAAI,iBAAiB,QAAQ,OAAO,EAAE;AAAA,IAC/C;AACA,YAAQ,IAAI,EAAE;AAEd,QAAI;AAEH,YAAM,EAAE,KAAK,IAAI,MAAM,mBAAmB,QAAQ,EAAE;AAEpD,UAAI;AAEH,cAAM,EAAE,WAAW,IAAI,MAAM,OAAO,qBAAqB;AAGzD,cAAM,kBAAkB,QAAQ,UAC7B,QAAQ,QAAQ,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAC9C;AACH,cAAM,kBAAkB,QAAQ,UAC7B,QAAQ,QAAQ,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAC9C;AAGH,cAAM,QAAQ,MAAM,WAAW,MAAM;AAAA,UACpC,QAAQ,QAAQ;AAAA,UAChB,GAAI,kBAAkB,EAAE,SAAS,gBAAgB,IAAI,CAAC;AAAA,UACtD,GAAI,kBAAkB,EAAE,SAAS,gBAAgB,IAAI,CAAC;AAAA,QACvD,CAAC;AAGD,cAAM,aAAa,MAAM,OAAO;AAChC,cAAM,gBAAgB,MAAM,UAAU;AACtC,cAAM,iBAAiB,MAAM,aAAa,UAAU;AAEpD,gBAAQ;AAAA,UACP,mBAAY,UAAU,YAAY,aAAa,eAAe,cAAc;AAAA,QAC7E;AAGA,cAAM,iBAAuC;AAAA,UAC5C,WAAW,QAAQ;AAAA,UACnB,uBAAuB,QAAQ;AAAA,UAC/B,gBAAgB,MAAM;AAAA,UACtB,UAAU,QAAQ;AAAA,QACnB;AAEA,cAAM,YAAY;AAAA,UACjB;AAAA,UACA;AAAA,QACD;AACA,cAAM,WAAW,eAAe,UAAU,QAAQ;AAClD,YAAI,SAAS,SAAS,GAAG;AACxB,yBAAe,QAAQ;AAAA,QACxB;AACA,gBAAQ,IAAI,EAAE;AAGd,cAAM,UAAUC,SAAQ,QAAQ,IAAI,GAAG,QAAQ,GAAG;AAClD,QAAAC,WAAUC,SAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/C,QAAAC,eAAc,SAAS,UAAU,MAAM,OAAO;AAE9C,gBAAQ,IAAI,4BAAuB,OAAO,EAAE;AAC5C,gBAAQ,IAAI,cAAc,UAAU,EAAE;AACtC,gBAAQ,IAAI,iBAAiB,aAAa,EAAE;AAAA,MAC7C,UAAE;AAED,cAAM,KAAK,IAAI;AAAA,MAChB;AAAA,IACD,SAAS,OAAO;AACf,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,cAAQ,MAAM,UAAK,OAAO,EAAE;AAC5B,cAAQ,KAAK,CAAC;AAAA,IACf;AAAA,EACD;AACD;;;AC/HD;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,WAAAC,gBAAe;;;AClBxB,SAAS,kBAAkB;AAC3B;AAAA,EACC;AAAA,EACA,aAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,OACM;AACP,SAAS,MAAM,WAAAC,gBAAe;AAsBvB,IAAM,yBAAyB;AAGtC,IAAM,6BAA6B;AAS5B,SAAS,gBAAgB,SAAyB;AACxD,SAAO,WAAW,QAAQ,EAAE,OAAO,SAAS,OAAO,EAAE,OAAO,KAAK;AAClE;AAaO,SAAS,0BACf,eACA,aACS;AACT,QAAM,SAAS,cAAc,OAAO,CAAC,KAAK,MAAM;AAC/C,UAAM,QAAQ,EAAE,MAAM,UAAU;AAChC,WAAO,QAAQ,CAAC,IAAI,KAAK,IAAI,KAAK,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI;AAAA,EACpE,GAAG,CAAC;AAEJ,QAAM,UAAU,OAAO,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;AAClD,QAAM,YAAY,YAChB,YAAY,EACZ,QAAQ,gBAAgB,GAAG,EAC3B,QAAQ,OAAO,GAAG,EAClB,QAAQ,UAAU,EAAE;AAEtB,SAAO,GAAG,OAAO,IAAI,aAAa,WAAW;AAC9C;AASO,SAAS,oBAAoB,KAAqB;AACxD,QAAM,WAAWA,SAAQ,GAAG;AAC5B,MAAI,CAAC,WAAW,QAAQ,GAAG;AAC1B,IAAAF,WAAU,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,EACxC;AACA,SAAO;AACR;AAMO,SAAS,mBAAmB,KAAuC;AACzE,QAAM,WAAWE,SAAQ,GAAG;AAC5B,MAAI,CAAC,WAAW,QAAQ,GAAG;AAC1B,WAAO,CAAC;AAAA,EACT;AAEA,QAAM,UAAU,YAAY,QAAQ,EAClC,OAAO,CAAC,MAAM,2BAA2B,KAAK,CAAC,CAAC,EAChD,KAAK;AAEP,SAAO,QAAQ,IAAI,CAAC,SAAS;AAC5B,UAAM,WAAW,KAAK,UAAU,IAAI;AACpC,UAAM,UAAU,aAAa,UAAU,OAAO;AAC9C,WAAO;AAAA,MACN;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,UAAU,gBAAgB,OAAO;AAAA,IAClC;AAAA,EACD,CAAC;AACF;AAOO,SAAS,mBACf,KACA,UACA,SACgB;AAChB,QAAM,UAAU,oBAAoB,GAAG;AACvC,QAAM,WAAW,KAAK,SAAS,QAAQ;AACvC,EAAAD,eAAc,UAAU,SAAS,OAAO;AAExC,SAAO;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN;AAAA,IACA,UAAU,gBAAgB,OAAO;AAAA,EAClC;AACD;;;ADnGO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACzC,YAAY,SAAiB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACb;AACD;AAYO,SAAS,gBAAgB,KAAqB;AACpD,MAAI,eAAe,OAAO;AAEzB,UAAM,OAAQ,IAAkC;AAChD,QAAI,OAAO,SAAS,YAAY,gBAAgB,KAAK,IAAI,GAAG;AAC3D,UAAI,QAAQ,IAAI,OAAO,SAAS,MAAM,GAAG;AACxC,gBAAQ,MAAM,4BAA4B,IAAI,OAAO,EAAE;AAAA,MACxD;AACA,aAAO,IAAI,eAAe,oCAAoC,IAAI,EAAE;AAAA,IACrE;AACA,WAAO;AAAA,EACR;AACA,SAAO,IAAI,MAAM,OAAO,GAAG,CAAC;AAC7B;AASA,eAAsB,gBACrB,OACA,IACa;AACb,QAAM,EAAE,KAAK,IAAI,MAAM,mBAAmB,KAAK;AAC/C,MAAI;AACH,WAAO,MAAM,GAAG,IAAI;AAAA,EACrB,UAAE;AACD,QAAI;AACJ,QAAI;AACH,YAAM,KAAK,IAAI;AAAA,IAChB,SAAS,GAAG;AACX,iBAAW;AAAA,IACZ;AACA,QAAI,aAAa,QAAW;AAE3B,cAAQ;AAAA,QACP,+BAA+B,oBAAoB,QAAQ,SAAS,UAAU,OAAO,QAAQ,CAAC;AAAA,MAC/F;AAAA,IACD;AAAA,EACD;AACD;AAMA,eAAe,iBAAiB,IAAwC;AACvE,MAAI;AACH,UAAM,GAAG;AAAA,EACV,SAAS,OAAO;AACf,QAAI,iBAAiB,OAAO;AAC3B,cAAQ,MAAM,iBAAY,MAAM,OAAO,EAAE;AAAA,IAC1C,OAAO;AACN,cAAQ,MAAM,+BAA0B;AAAA,IACzC;AACA,YAAQ,KAAK,CAAC;AAAA,EACf;AACD;AASO,SAAS,iBAAiB,MAAuB;AACvD,SAAO,KAAK,MAAM,IAAI,EAAE,KAAK,CAAC,SAAS;AACtC,UAAM,IAAI,KAAK,KAAK;AACpB,WAAO,EAAE,SAAS,KAAK,CAAC,EAAE,WAAW,IAAI;AAAA,EAC1C,CAAC;AACF;AAwCA,IAAM,qBAA4C;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAEA,SAAS,mBAAmB,MAA2C;AACtE,SAAO,EAAE,GAAG,oBAAoB,GAAG,KAAK;AACzC;AAEA,eAAsB,SACrB,SACA,MACgB;AAChB,QAAM,IAAI,mBAAmB,IAAI;AAEjC,UAAQ,IAAI,+BAAwB;AACpC,UAAQ,IAAI,gBAAgB,YAAY,QAAQ,EAAE,CAAC,EAAE;AACrD,UAAQ,IAAI,iBAAiB,QAAQ,GAAG,EAAE;AAC1C,UAAQ,IAAI,EAAE;AAEd,QAAM,EAAE,gBAAgB,QAAQ,IAAI,OAAO,SAAS;AAEnD,UAAM,EAAE,sBAAsB,IAAI;AAElC,UAAM,EAAE,kBAAkB,MAAM,OAAO,WAAW;AAEjD,YAAM,UAAU,MAAM,EAAE,qBAAqB,MAAyB;AACtE,YAAM,aAAa,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAGnE,YAAM,QAAQ,EAAE,mBAAmB,QAAQ,GAAG;AAE9C,UAAI,MAAM,WAAW,GAAG;AACvB,gBAAQ,IAAI,+BAA+B,QAAQ,GAAG,EAAE;AACxD;AAAA,MACD;AAGA,iBAAW,QAAQ,OAAO;AACzB,cAAM,mBAAmB,WAAW,IAAI,KAAK,IAAI;AACjD,YACC,qBAAqB,UACrB,qBAAqB,KAAK,UACzB;AACD,gBAAM,IAAI;AAAA,YACT,yBAAyB,KAAK,IAAI;AAAA,eACjB,gBAAgB;AAAA,eAChB,KAAK,QAAQ;AAAA;AAAA;AAAA,UAE/B;AAAA,QACD;AAAA,MACD;AAGA,YAAM,UAAU,MAAM,OAAO,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,IAAI,CAAC;AAE3D,UAAI,QAAQ,WAAW,GAAG;AACzB,gBAAQ,IAAI,wCAAmC;AAC/C;AAAA,MACD;AAEA,UAAI,QAAQ,QAAQ;AACnB,gBAAQ,IAAI,GAAG,QAAQ,MAAM,wBAAwB;AACrD,mBAAW,QAAQ,SAAS;AAC3B,kBAAQ,IAAI,QAAQ,KAAK,IAAI,EAAE;AAAA,QAChC;AACA;AAAA,MACD;AAGA,UAAI,eAAe;AACnB,iBAAW,QAAQ,SAAS;AAC3B,gBAAQ,IAAI,eAAe,KAAK,IAAI,KAAK;AAGzC,cAAM,SAAS,EAAE,mBAAmB,KAAK,OAAO;AAChD,cAAM,aAAa,OAAO,aAAa,OAAO,gBAAgB;AAI9D,cAAM,UAAU,MAAM,EAAE,qBAAqB,MAAyB;AACtE,cAAM,cAAc,OAAO,gBAAgB;AAG3C,YAAI;AACH,gBAAM,OAAO,MAAM,OAAO;AAE1B,qBAAW,QAAQ,YAAY;AAC9B,kBAAM,OAAO,MAAM,IAAI;AAAA,UACxB;AAEA,gBAAM,EAAE;AAAA,YACP;AAAA,YACA,KAAK;AAAA,YACL,KAAK;AAAA,YACL;AAAA,YACA;AAAA,UACD;AAEA,gBAAM,OAAO,MAAM,QAAQ;AAAA,QAC5B,SAAS,YAAY;AACpB,cAAI;AACJ,cAAI;AACH,kBAAM,OAAO,MAAM,UAAU;AAAA,UAC9B,SAAS,GAAG;AACX,4BAAgB;AAAA,UACjB;AACA,gBAAM,UAAU,gBAAgB,UAAU;AAC1C,cAAI,kBAAkB,QAAW;AAChC,oBAAQ;AAAA,cACP,kCAAkC,gBAAgB,aAAa,EAAE,OAAO;AAAA,YACzE;AAAA,UACD;AACA,gBAAM;AAAA,QACP;AAEA;AACA,gBAAQ,IAAI,qBAAgB,KAAK,IAAI,EAAE;AAAA,MACxC;AAEA,cAAQ,IAAI;AAAA,SAAO,YAAY,qCAAqC;AAAA,IACrE,CAAC;AAAA,EACF,CAAC;AACF;AAEA,eAAsB,YACrB,SACA,MACgB;AAChB,QAAM,IAAI,mBAAmB,IAAI;AAEjC,UAAQ,IAAI,uBAAkB,QAAQ,KAAK,eAAe;AAC1D,UAAQ,IAAI,gBAAgB,YAAY,QAAQ,EAAE,CAAC,EAAE;AACrD,UAAQ,IAAI,iBAAiB,QAAQ,GAAG,EAAE;AAC1C,UAAQ,IAAI,EAAE;AAEd,QAAM,EAAE,gBAAgB,QAAQ,IAAI,OAAO,SAAS;AACnD,UAAM,EAAE,sBAAsB,IAAI;AAElC,UAAM,EAAE,kBAAkB,MAAM,OAAO,WAAW;AAEjD,YAAM,UAAU,MAAM,EAAE,qBAAqB,MAAyB;AACtE,YAAM,aAAa,CAAC,GAAG,OAAO,EAAE;AAAA,QAAK,CAAC,GAAG,MACxC,EAAE,KAAK,cAAc,EAAE,IAAI;AAAA,MAC5B;AAGA,UAAI,QAAQ,QAAQ,WAAW,QAAQ;AACtC,cAAM,IAAI;AAAA,UACT,oBAAoB,QAAQ,KAAK,6BAAwB,WAAW,MAAM;AAAA,QAC3E;AAAA,MACD;AAEA,YAAM,aAAa,WAAW,MAAM,GAAG,QAAQ,KAAK;AAGpD,YAAM,QAAQ,EAAE,mBAAmB,QAAQ,GAAG;AAC9C,YAAM,UAAU,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAErD,UAAI,aAAa;AACjB,iBAAW,UAAU,YAAY;AAChC,cAAM,OAAO,QAAQ,IAAI,OAAO,IAAI;AACpC,YAAI,CAAC,MAAM;AACV,gBAAM,IAAI;AAAA,YACT,qCAAqC,OAAO,IAAI;AAAA,UACjD;AAAA,QACD;AAGA,YAAI,KAAK,aAAa,OAAO,UAAU;AACtC,gBAAM,IAAI;AAAA,YACT,yBAAyB,OAAO,IAAI;AAAA,eACnB,OAAO,QAAQ;AAAA,eACf,KAAK,QAAQ;AAAA;AAAA;AAAA,UAE/B;AAAA,QACD;AAGA,cAAM,SAAS,EAAE,mBAAmB,KAAK,OAAO;AAGhD,YAAI,CAAC,OAAO,SAAS;AACpB,gBAAM,IAAI;AAAA,YACT,aAAa,OAAO,IAAI;AAAA;AAAA,UAEzB;AAAA,QACD;AAGA,cAAM,YAAY,OAAO,eAAe,OAAO,gBAAgB;AAC/D,YAAI,UAAU,WAAW,KAAK,CAAC,QAAQ,OAAO;AAC7C,gBAAM,IAAI;AAAA,YACT,aAAa,OAAO,IAAI;AAAA;AAAA,UAEzB;AAAA,QACD;AAGA,cAAM,+BACL,OAAO,gBAAgB,SAAS,EAAE,kBAAkB,SAAS;AAC9D,aACE,OAAO,gBAAgB,SAAS,iCACjC,CAAC,QAAQ,OACR;AACD,cAAI,OAAO,gBAAgB,MAAM;AAChC,kBAAM,IAAI;AAAA,cACT,aAAa,OAAO,IAAI;AAAA;AAAA,YAEzB;AAAA,UACD;AACA,cAAI,8BAA8B;AACjC,kBAAM,IAAI;AAAA,cACT,aAAa,OAAO,IAAI;AAAA;AAAA,YAEzB;AAAA,UACD;AACA,gBAAM,IAAI;AAAA,YACT,aAAa,OAAO,IAAI;AAAA;AAAA,UAEzB;AAAA,QACD;AAGA,YAAI,UAAU,SAAS,KAAK,QAAQ,OAAO;AAC1C,kBAAQ,IAAI,mBAAmB,OAAO,IAAI,KAAK;AAAA,QAChD;AAEA,YAAI;AACH,gBAAM,OAAO,MAAM,OAAO;AAE1B,qBAAW,QAAQ,WAAW;AAC7B,kBAAM,OAAO,MAAM,IAAI;AAAA,UACxB;AAEA,gBAAM,EAAE,sBAAsB,QAA2B,OAAO,IAAI;AAEpE,gBAAM,OAAO,MAAM,QAAQ;AAAA,QAC5B,SAAS,eAAe;AACvB,cAAI;AACJ,cAAI;AACH,kBAAM,OAAO,MAAM,UAAU;AAAA,UAC9B,SAAS,GAAG;AACX,mCAAuB;AAAA,UACxB;AACA,gBAAM,UAAU,gBAAgB,aAAa;AAC7C,cAAI,yBAAyB,QAAW;AACvC,oBAAQ;AAAA,cACP,kCAAkC,gBAAgB,oBAAoB,EAAE,OAAO;AAAA,YAChF;AAAA,UACD;AACA,gBAAM;AAAA,QACP;AAEA;AACA,gBAAQ,IAAI,yBAAoB,OAAO,IAAI,EAAE;AAAA,MAC9C;AAEA,cAAQ,IAAI;AAAA,SAAO,UAAU,yCAAyC;AAAA,IACvE,CAAC;AAAA,EACF,CAAC;AACF;AAEA,SAAS,mBACR,UACA,SACgB;AAChB,QAAM,QAAQ,OAAO,SAAS,UAAU,EAAE;AAC1C,MAAI,OAAO,MAAM,KAAK,KAAK,QAAQ,GAAG;AACrC,YAAQ,MAAM,yCAAoC;AAClD,YAAQ,KAAK,CAAC;AAAA,EACf;AAEA,SAAO,iBAAiB,YAAY;AACnC,UAAM,YAAY,EAAE,OAAO,GAAG,QAAQ,CAAC;AAAA,EACxC,CAAC;AACF;AAMA,IAAM,aAAa,IAAIE,SAAQ,KAAK,EAClC,YAAY,0CAA0C,EACtD;AAAA,EACA;AAAA,EACA;AACD,EACC,eAAe,kBAAkB,oCAAoC,EACrE,OAAO,wBAAwB,wCAAwC,EACvE,OAAO,gBAAgB,wBAAwB,sBAAsB,EACrE,OAAO,4BAA4B,yBAAyB,WAAW,EACvE,OAAO,uBAAuB,qCAAqC,EACnE;AAAA,EACA,CAAC,YAQA,iBAAiB,YAAY;AAC5B,UAAM,aAAa,QAAQ,UAAU;AAErC,YAAQ,IAAI,mCAA4B,UAAU,EAAE;AACpD,YAAQ,IAAI,gBAAgB,YAAY,QAAQ,EAAE,CAAC,EAAE;AACrD,YAAQ,IAAI,EAAE;AAEd,UAAM,SAAS,MAAM,WAAW,UAAU;AAC1C,UAAM,cAAc,OAAO;AAE3B,UAAM,gBAAgB,QAAQ,IAAI,OAAO,SAAS;AACjD,YAAM,UAAU,mBAAmB,IAAI;AACvC,YAAM,OAAO,MAAM,2BAA2B,SAAS,aAAa;AAAA,QACnE,GAAI,QAAQ,aAAa,EAAE,QAAQ,QAAQ,WAAW,IAAI,CAAC;AAAA,QAC3D,GAAI,OAAO,WAAW,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;AAAA,QACvD,qCAAqC,CAAC,YACrC,QAAQ;AAAA,UACP,kBAAQ,QAAQ,IAAI,IAAI,qBAAqB,QAAQ,KAAK,CAAC,IAAI,qBAAqB,QAAQ,IAAI,CAAC,KAAK,QAAQ,OAAO;AAAA,QACtH;AAAA,MACF,CAAC;AAED,UAAI,KAAK,QAAQ,WAAW,GAAG;AAC9B,gBAAQ,IAAI,4DAAkD;AAC9D;AAAA,MACD;AAGA,UAAI,KAAK,kBAAkB,CAAC,QAAQ,kBAAkB;AACrD,cAAM,cAAc,KAAK,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW;AAC5D,cAAM,IAAI;AAAA,UACT,GAAG,YAAY,MAAM;AAAA,IACpB,YAAY,IAAI,CAAC,MAAM,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,IAAI,IACrD;AAAA,QACF;AAAA,MACD;AAEA,YAAM,aAAa;AAAA,QAClB,oBAAoB,QAAQ,oBAAoB;AAAA,QAChD,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,MAChE;AAEA,YAAM,aAAa,qBAAqB,MAAM,UAAU;AAExD,UAAI,WAAW,WAAW,GAAG;AAC5B,gBAAQ;AAAA,UACP;AAAA,QACD;AACA;AAAA,MACD;AAGA,YAAM,gBAAgB,mBAAmB,QAAQ,GAAG,EAAE;AAAA,QACrD,CAAC,MAAM,EAAE;AAAA,MACV;AACA,YAAM,WAAW;AAAA,QAChB;AAAA,QACA,QAAQ;AAAA,MACT;AACA,YAAM,UAAU,sBAAsB,MAAM;AAAA,QAC3C,GAAG;AAAA,QACH,MAAM;AAAA,MACP,CAAC;AAED,YAAM,OAAO,mBAAmB,QAAQ,KAAK,UAAU,OAAO;AAE9D,cAAQ,IAAI,6BAAwB,KAAK,IAAI,EAAE;AAC/C,cAAQ,IAAI,kBAAkB,WAAW,MAAM,EAAE;AACjD,cAAQ,IAAI,gBAAgB,KAAK,SAAS,MAAM,GAAG,EAAE,CAAC,KAAK;AAAA,IAC5D,CAAC;AAAA,EACF,CAAC;AACH;AAED,IAAM,eAAe,IAAIA,SAAQ,OAAO,EACtC,YAAY,0BAA0B,EACtC,eAAe,kBAAkB,oCAAoC,EACrE,OAAO,gBAAgB,wBAAwB,sBAAsB,EACrE,OAAO,aAAa,0CAA0C,EAC9D;AAAA,EAAO,CAAC,YACR,iBAAiB,YAAY;AAC5B,UAAM,SAAS,OAAO;AAAA,EACvB,CAAC;AACF;AAED,IAAM,kBAAkB,IAAIA,SAAQ,UAAU,EAC5C,YAAY,8BAA8B,EAC1C,SAAS,WAAW,mCAAmC,EACvD,eAAe,kBAAkB,oCAAoC,EACrE,OAAO,gBAAgB,wBAAwB,sBAAsB,EACrE,OAAO,WAAW,wDAAwD,EAC1E,OAAO,kBAAkB;AAE3B,IAAM,gBAAgB,IAAIA,SAAQ,QAAQ,EACxC,YAAY,uBAAuB,EACnC,eAAe,kBAAkB,oCAAoC,EACrE,OAAO,gBAAgB,wBAAwB,sBAAsB,EACrE,OAAO,UAAU,gBAAgB,EACjC;AAAA,EAAO,CAAC,YACR,iBAAiB,YAAY;AAC5B,UAAM,gBAAgB,QAAQ,IAAI,OAAO,SAAS;AACjD,YAAM,sBAAsB,IAAI;AAEhC,YAAM,UAAU,MAAM,qBAAqB,IAAI;AAC/C,YAAM,aAAa,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAE1D,YAAM,QAAQ,mBAAmB,QAAQ,GAAG;AAE5C,YAAM,WAID,MAAM,IAAI,CAAC,SAAS;AACxB,cAAM,SAAS,WAAW,IAAI,KAAK,IAAI;AACvC,YAAI,WAAW,QAAW;AACzB,iBAAO;AAAA,YACN,MAAM,KAAK;AAAA,YACX,QAAQ;AAAA,UACT;AAAA,QACD;AACA,YAAI,OAAO,aAAa,KAAK,UAAU;AACtC,iBAAO;AAAA,YACN,MAAM,KAAK;AAAA,YACX,QAAQ;AAAA,YACR,WAAW,OAAO;AAAA,UACnB;AAAA,QACD;AACA,eAAO;AAAA,UACN,MAAM,KAAK;AAAA,UACX,QAAQ;AAAA,UACR,WAAW,OAAO;AAAA,QACnB;AAAA,MACD,CAAC;AAGD,iBAAW,UAAU,SAAS;AAC7B,YAAI,CAAC,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,IAAI,GAAG;AAC/C,mBAAS,KAAK;AAAA,YACb,MAAM,OAAO;AAAA,YACb,QAAQ;AAAA,YACR,WAAW,OAAO;AAAA,UACnB,CAAC;AAAA,QACF;AAAA,MACD;AAEA,UAAI,QAAQ,MAAM;AACjB,gBAAQ,IAAI,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,MAC9C,OAAO;AACN,gBAAQ,IAAI,kBAAkB;AAC9B,gBAAQ,IAAI,gBAAgB,YAAY,QAAQ,EAAE,CAAC,EAAE;AACrD,gBAAQ,IAAI,iBAAiB,QAAQ,GAAG,EAAE;AAC1C,gBAAQ,IAAI,EAAE;AAEd,YAAI,SAAS,WAAW,GAAG;AAC1B,kBAAQ,IAAI,sBAAsB;AAAA,QACnC,OAAO;AACN,qBAAW,KAAK,UAAU;AACzB,kBAAM,OACL,EAAE,WAAW,YACV,WACA,EAAE,WAAW,YACZ,WACA,EAAE,WAAW,sBACZ,iBACA;AACN,kBAAM,SACL,eAAe,KAAK,EAAE,YACnB,cAAc,EAAE,UAAU,YAAY,CAAC,MACvC;AACJ,oBAAQ,IAAI,KAAK,IAAI,IAAI,EAAE,IAAI,WAAM,EAAE,MAAM,GAAG,MAAM,EAAE;AAAA,UACzD;AAEA,gBAAM,eAAe,SAAS;AAAA,YAC7B,CAAC,MAAM,EAAE,WAAW;AAAA,UACrB,EAAE;AACF,gBAAM,eAAe,SAAS;AAAA,YAC7B,CAAC,MAAM,EAAE,WAAW;AAAA,UACrB,EAAE;AAEF,kBAAQ,IAAI,EAAE;AACd,kBAAQ;AAAA,YACP,UAAU,SAAS,MAAM,eAAe,YAAY,eAAe,YAAY;AAAA,UAChF;AAAA,QACD;AAAA,MACD;AAAA,IACD,CAAC;AAAA,EACF,CAAC;AACF;AAMM,IAAM,iBAAiB,IAAIA,SAAQ,SAAS,EACjD,YAAY,+BAA+B,EAC3C,WAAW,UAAU,EACrB,WAAW,YAAY,EACvB,WAAW,eAAe,EAC1B,WAAW,aAAa;;;AErqB1B;AAAA,EACC;AAAA,EACA;AAAA,EACA,sBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,wBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGM;AAWP,SAAS,WAAAC,gBAAe;AA4BjB,IAAM,oCAAN,cAAgD,MAAM;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YACC,QACA,kBACA,UAA0B,kBACzB;AACD,UAAM,QACL,QAAQ,SAAS,WACd,IAAI;AAAA,MACJ,CAAC,kBAAkB,QAAQ,KAAK;AAAA,MAChC;AAAA,IACD,IACC;AACJ;AAAA,MACC,0CAA0C,OAAO,KAAK,KAAKC,sBAAqB,eAAe,gBAAgB,CAAC,CAAC;AAAA,MACjH,EAAE,MAAM;AAAA,IACT;AACA,SAAK,OAAO;AACZ,SAAK,QAAQ,OAAO,SAAS;AAC7B,SAAK,SAAS;AACd,SAAK,mBAAmB;AACxB,SAAK,UAAU;AAAA,EAChB;AACD;AAGO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC3C,YACU,QACA,cACR;AACD;AAAA,MACC,oEAAoEA,sBAAqB,eAAe,YAAY,CAAC,CAAC;AAAA,MACtH,EAAE,OAAO,aAAa;AAAA,IACvB;AANS;AACA;AAMT,SAAK,OAAO;AAAA,EACb;AAAA,EARU;AAAA,EACA;AAQX;AAGA,IAAM,+BAAN,cAA2C,eAAe;AAAA,EACzD,YACU,gBACA,cACR;AACD;AAAA,MACC,CAAC,gBAAgB,YAAY;AAAA,MAC7B;AAAA,MACA,EAAE,OAAO,eAAe;AAAA,IACzB;AAPS;AACA;AAOT,SAAK,OAAO;AAAA,EACb;AAAA,EATU;AAAA,EACA;AASX;AASA,IAAM,mBAAmC,EAAE,MAAM,aAAa;AA8D9D,SAAS,mBAAmB,SAA6B;AACxD,SAAO;AAAA,IACN,QAAQ,QAAQ;AAAA,IAChB,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,IAC/D,GAAI,QAAQ,eAAe,EAAE,cAAc,QAAQ,aAAa,IAAI,CAAC;AAAA,IACrE,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,IAC/D,yBAAyB;AAAA,EAC1B;AACD;AAGO,SAAS,0BACf,MACA,gBACoB;AACpB,QAAM,aAAa;AAAA,IAClB,GAAG,IAAI;AAAA,MACN,KAAK,MAAM,IAAI,CAAC,SAAS;AACxB,cAAM,UAAU,KAAK,UAAU;AAC/B,YACC,YAAY,QACZ,OAAO,YAAY,YACnB,MAAM,QAAQ,OAAO,KACrB,OAAQ,QAAoC,WAAW;AAEvD,gBAAM,IAAI;AAAA,YACT,KAAK,UAAU;AAAA,YACf,KAAK,UAAU,cAAc;AAAA,YAC7B;AAAA,UACD;AACD,eAAQ,QAAoC;AAAA,MAC7C,CAAC;AAAA,IACF;AAAA,EACD;AACA,MAAI,WAAW,WAAW,KAAK,mBAAmB;AACjD,eAAW,KAAK,cAAc;AAC/B,SAAO;AACR;AAGA,eAAsB,yBACrB,MACA,QACA,MACA,wBAC6B;AAC7B,QAAM,QAAQ,MAAM,uBAAuB,yBAAyB,IAAI,CAAC;AACzE,MAAI;AACH,UAAM,SAAS,MAAM;AAAA,MACpB,MAAM;AAAA,MACN,0BAA0B,MAAM,MAAM;AAAA,IACvC;AACA,UAAM,WAAW;AAAA,MAChB;AAAA,MACA,OAAO;AAAA,IACR;AACA,QAAI,UAAU;AACb,YAAM,IAAI;AAAA,QACT,+DAA+D,QAAQ;AAAA,MACxE;AAAA,IACD;AACA,WAAO;AAAA,MACN;AAAA,MACA,OAAO;AAAA,MACP,OAAO;AAAA,IACR;AAAA,EACD,UAAE;AACD,UAAM,MAAM,QAAQ;AAAA,EACrB;AACD;AAEA,IAAM,kBAA4B;AAAA,EACjC,MAAM,mBAAmB,IAAI;AAC5B,UAAM,EAAE,KAAK,IAAI,MAAM,mBAAmB,EAAE;AAC5C,WAAO,EAAE,MAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAAA,EAC1C;AAAA,EACA;AAAA,EACA,MAAM,wBAAwB,MAAM;AACnC,UAAM,QAAQ,MAAM,uBAAuB,yBAAyB,IAAI,CAAC;AACzE,QAAI;AACH,YAAM,wBAAwB,MAAM,OAAO;AAAA,IAC5C,UAAE;AACD,YAAM,MAAM,QAAQ;AAAA,IACrB;AAAA,EACD;AAAA,EACA,MAAM,sBAAsB,MAAM,QAAQ;AACzC,UAAM,QAAQ,MAAM,uBAAuB,yBAAyB,IAAI,CAAC;AACzE,QAAI;AACH,cACC,MAAM,gCAAgC,MAAM,SAAS;AAAA,QACpD,UAAU;AAAA,MACX,CAAC,GACA;AAAA,IACH,UAAE;AACD,YAAM,MAAM,QAAQ;AAAA,IACrB;AAAA,EACD;AAAA,EACA,MAAM,YAAY,MAAM,QAAQ,wBAAwB;AACvD,UAAM,QAAQ,MAAM,0BAA0B,IAAI;AAClD,QAAI;AACH,YAAM,WAAW,MAAM;AAAA,QACtB,MAAM;AAAA,QACN,CAAC,UAAU,QAAQ;AAAA,MACpB;AACA,YAAM,WAAW;AAAA,QAChB;AAAA,QACA,SAAS;AAAA,MACV;AACA,UAAI,UAAU;AACb,cAAM,IAAI;AAAA,UACT,gFAAgF,QAAQ;AAAA,QACzF;AAAA,MACD;AACA,aAAO,MAAMC,oBAAmB,MAAM,QAAQ;AAAA,QAC7C,gBAAgB;AAAA,MACjB,CAAC,EAAE,WAAW,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO,CAAC;AAAA,IACrD,UAAE;AACD,YAAM,QAAQ;AAAA,IACf;AAAA,EACD;AAAA,EACA,MAAM,YAAY,MAAM,QAAQ,wBAAwB;AACvD,WAAO;AAAA,MACN,yBAAyB,IAAI;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA,EACA,cAAc,QAAQ;AACrB,UAAM,WAAW,mBAAmB;AAAA,MACnC,uBAAuB;AAAA,QACtB,GAAI,OAAO,WAAW,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;AAAA,MACxD,CAAC;AAAA,IACF,CAAC;AACD,UAAM,aAAa,iBAAiB,QAAQ;AAC5C,UAAM,SAAS,aAAa,QAAQ;AACpC,WAAO;AAAA,MACN,SAAS,CAAC,SAAS,SAAS,YAC3B,WAAW,QAAQ,SAAS,SAAS,mBAAmB,OAAO,CAAC;AAAA,MACjE,OAAO,CAAC,SAAS,MAAM,YACtB,OAAO,MAAM,SAAS,yBAAyB,IAAI,GAAG,OAAO;AAAA,MAC9D,QAAQ,CAAC,MAAM,YAAY,oBAAoB,UAAU,MAAM,OAAO;AAAA,IACvE;AAAA,EACD;AAAA,EACA,MAAM,QAAQ,MAAM,KAAK,MAAM;AAC9B,UAAM,QAAQ,MAAM,uBAAuB,yBAAyB,IAAI,CAAC;AACzE,QAAI;AACH,YAAM,+BAA+B,MAAM,OAAO,EAAE,QAAQ,KAAK,IAAI;AAAA,IACtE,UAAE;AACD,YAAM,MAAM,QAAQ;AAAA,IACrB;AAAA,EACD;AAAA,EACA,wBAAwB;AACzB;AAEA,SAAS,aAAa,WAAyC;AAC9D,SAAO,EAAE,GAAG,iBAAiB,GAAG,UAAU;AAC3C;AAEA,SAAS,eAAe,OAAwB;AAC/C,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC7D;AAEA,SAAS,mCACR,OACiB;AACjB,SAAO;AAAA,IACN,UAAU;AAAA,IACV,WAAW;AAAA,IACX,WAAW;AAAA,IACX,cAAc;AAAA,IACd,SAAS;AAAA,MACR;AAAA,QACC,MAAM;AAAA,QACN,SAAS,CAAC;AAAA,QACV,OAAO,CAAC;AAAA,QACR,QAAQ,MAAM;AAAA,MACf;AAAA,IACD;AAAA,EACD;AACD;AAGO,SAAS,oBACf,UACA,MACA,SACS;AACT,QAAM,aAAa,KAAK,MAAM,IAAI,CAAC,SAAS;AAC3C,UAAM,aAAa,SAAS,iBAAiB,KAAK,SAAS;AAC3D,QAAI,CAAC,WAAW,MAAM,CAAC,WAAW,UAAU,eAAe;AAC1D,YAAM,IAAI;AAAA,QACT,sDAAsD,KAAK,UAAU,cAAc,IAAI;AAAA,MACxF;AAAA,IACD;AACA,WAAO,WAAW,UAAU,cAAc,KAAK,WAAW,OAAO;AAAA,EAClE,CAAC;AACD,SAAO;AAAA,IACN;AAAA,IACA,GAAG,WAAW,IAAI,CAAC,cAAc,GAAG,SAAS,GAAG;AAAA,EACjD,EAAE,KAAK,IAAI;AACZ;AAEA,eAAsB,QACrB,SACA,WACsB;AACtB,QAAM,OAAO,aAAa,SAAS;AACnC,QAAM,SAAS,QAAQ,UAAU;AACjC,MAAI,WAAW,SAAS,WAAW,QAAQ;AAC1C,UAAM,IAAI,MAAM,2BAA2B,MAAM,wBAAwB;AAAA,EAC1E;AACA,QAAM,SAAS,MAAM,KAAK,WAAW,QAAQ,UAAU;AACvD,QAAM,aAAa,MAAM,KAAK,mBAAmB,QAAQ,EAAE;AAC3D,QAAM,EAAE,KAAK,IAAI;AACjB,MAAI;AACJ,MAAI;AACJ,MAAI,SAAS;AACb,MAAI;AAGH,UAAM,iBAAiB,MAAM,KAAK;AAAA,MACjC;AAAA,MACA,QAAQ;AAAA,IACT;AACA,UAAM,KAAK,wBAAwB,IAAI;AACvC,UAAM,UAAU,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACD;AACA,UAAM,UAAU,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACD;AACA,UAAM,UAAU,KAAK,cAAc,MAAM;AACzC,UAAM,UAAU,QAAQ,QAAQ,OAAO,OAAO,SAAS,OAAO;AAC9D,UAAM,QAAQ,MAAM,QAAQ,MAAM,SAAS,MAAM,OAAO;AAExD,QAAI,MAAM,SAAS,UAAU;AAC5B,UAAI;AACJ,UAAI;AACH,4BAAoB,MAAM,KAAK;AAAA,UAC9B;AAAA,UACA,QAAQ;AAAA,UACR,MAAM;AAAA,UACN;AAAA,QACD;AAAA,MACD,SAAS,OAAO;AACf,YAAI,EAAE,iBAAiB,oCAAqC,OAAM;AAClE,iBAAS;AAAA,UACR,aAAa,QAAQ;AAAA,UACrB,WAAW;AAAA,UACX,YAAY,mCAAmC,KAAK;AAAA,UACpD,WAAW;AAAA,UACX,OAAO;AAAA,UACP,YAAY;AAAA,QACb;AAAA,MACD;AACA,UAAI,sBAAsB,QAAW;AAGpC,cAAM,cAAc;AAAA,UACnB,MAAM;AAAA,UACN;AAAA,QACD;AACA,cAAM,MAAM,4BAA4B,WAAW;AACnD,cAAM,eAAe,MAAM,KAAK,aAAa;AAAA,UAC5C,CAAC,gBAAgB,YAAY,SAAS;AAAA,QACvC,GAAG;AACH,YAAI,CAAC,cAAc;AAClB,gBAAM,IAAI;AAAA,YACT;AAAA,UACD;AAAA,QACD;AACA,cAAM,MAAM,QAAQ,OAAO,aAAa,YAAY;AACpD,YAAI,CAAC,QAAQ,QAAQ;AACpB,cAAI;AACH,kBAAM,KAAK,QAAQ,MAAM,KAAK,WAAW;AAAA,UAC1C,SAAS,OAAO;AACf,kBAAM,IAAI;AAAA,cACT;AAAA,gBACC,aAAa,QAAQ;AAAA,gBACrB,WAAW,MAAM;AAAA,gBACjB,YAAY,MAAM;AAAA,gBAClB,WAAW;AAAA,gBACX,OAAO,IAAI;AAAA,gBACX,YAAY,IAAI;AAAA,cACjB;AAAA,cACA;AAAA,YACD;AAAA,UACD;AAAA,QACD;AACA,iBAAS;AAAA,UACR,aAAa,QAAQ;AAAA,UACrB,WAAW,MAAM;AAAA,UACjB,YAAY,MAAM;AAAA,UAClB,WAAW,CAAC,QAAQ;AAAA,UACpB,OAAO,QAAQ,SAAS,OAAO,IAAI;AAAA,UACnC,YAAY,IAAI;AAAA,UAChB,MAAM;AAAA,UACN;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,QAAI,MAAM,SAAS,YAAY;AAC9B,eAAS;AAAA,QACR,aAAa,QAAQ;AAAA,QACrB,WAAW,MAAM;AAAA,QACjB,YAAY,MAAM;AAAA,QAClB,WAAW;AAAA,QACX,OAAO;AAAA,QACP,YAAY;AAAA,MACb;AAAA,IACD,WAAW,MAAM,SAAS,UAAU;AACnC,eAAS;AAAA,QACR,aAAa,QAAQ;AAAA,QACrB,WAAW,MAAM;AAAA,QACjB,YAAY,MAAM;AAAA,QAClB,WAAW;AAAA,QACX,OAAO;AAAA,QACP,YAAY;AAAA,MACb;AAAA,IACD;AAAA,EACD,SAAS,OAAO;AACf,aAAS;AACT,qBAAiB;AAAA,EAClB;AAEA,MAAI,UAA0B;AAC9B,MAAI;AACH,UAAM,WAAW,QAAQ;AAAA,EAC1B,SAAS,OAAO;AACf,cAAU,EAAE,MAAM,UAAU,MAAM;AAAA,EACnC;AAEA,MAAI,QAAQ;AACX,QAAI,0BAA0B,mCAAmC;AAChE,YAAM,IAAI;AAAA,QACT,eAAe;AAAA,QACf,eAAe;AAAA,QACf;AAAA,MACD;AAAA,IACD;AACA,QAAI,QAAQ,SAAS,UAAU;AAC9B,YAAM,IAAI,6BAA6B,gBAAgB,QAAQ,KAAK;AAAA,IACrE;AACA,UAAM;AAAA,EACP;AACA,MAAI,QAAQ,SAAS,UAAU;AAC9B,UAAM,IAAI,iBAAiB,QAAsB,QAAQ,KAAK;AAAA,EAC/D;AACA,SAAO;AACR;AAEO,SAAS,eAAe,QAAoB,QAAiB;AACnE,SAAO;AAAA,IACN,aAAa,OAAO;AAAA,IACpB,WAAW,OAAO;AAAA,IAClB,YAAY,OAAO;AAAA,IACnB,WAAW,OAAO;AAAA,IAClB,OAAO,OAAO;AAAA,IACd,YAAY,OAAO;AAAA,IACnB,GAAI,OAAO,OAAO,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,IAC3C,GAAI,OAAO,MAAM,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC;AAAA,IACxC,GAAI,UAAU,OAAO,cAAc,WAChC,EAAE,SAAS,yCAAyC,IACpD,CAAC;AAAA,EACL;AACD;AAEO,SAAS,gBAAgB,QAAoB,QAAyB;AAC5E,MAAI,OAAO,cAAc,UAAU;AAClC,WAAO;AAAA,MACN,SACG,wEACA;AAAA;AAAA;AAAA,MAGH,GAAI,OAAO,QAAQ,SAAY,CAAC,IAAI,CAACD,sBAAqB,OAAO,GAAG,CAAC;AAAA,MACrE,GAAI,OAAO,MAAM,oBACd;AAAA,QACA;AAAA,QACA,GAAG,OAAO,KAAK,kBAAkB,aAAa;AAAA,UAC7C,CAAC,gBACA,KAAKA,sBAAqB,KAAK,UAAU,WAAW,CAAC,CAAC;AAAA,QACxD;AAAA,MACD,IACC,CAAC;AAAA,MACJ,SACG,mBAAmB,OAAO,UAAU,KACpC,WAAW,OAAO,KAAK;AAAA,eAAkB,OAAO,UAAU;AAAA,IAC9D,EACE,OAAO,CAAC,SAAyB,SAAS,MAAS,EACnD,KAAK,IAAI;AAAA,EACZ;AACA,MAAI,OAAO,cAAc,YAAY;AACpC,WAAO;AAAA,EACR;AACA,SAAO;AAAA,EAAiCA,sBAAqB,KAAK,UAAU,OAAO,YAAY,MAAM,CAAC,CAAC,CAAC;AACzG;AAEA,SAAS,oBACR,OACA,UACyB;AACzB,MAAI,iBAAiB,kCAAmC,QAAO,MAAM;AACrE,MAAI,iBAAiB,iBAAkB,QAAO,MAAM;AACpD,SAAO;AACR;AAEA,SAAS,iBAAiB,OAAyB;AAClD,MAAI,iBAAiB,mCAAmC;AACvD,WAAO,MAAM;AAAA,EACd;AACA,MAAI,iBAAiB,iBAAkB,QAAO,MAAM;AACpD,MAAI,iBAAiB,8BAA8B;AAClD,WAAO,MAAM;AAAA,EACd;AACA,SAAO;AACR;AAEA,SAAS,eAAe,OAAgC;AACvD,MAAI,iBAAiB,mCAAmC;AACvD,WAAO,MAAM;AAAA,EACd;AACA,MAAI,iBAAiB,kBAAkB;AACtC,WAAO,EAAE,MAAM,UAAU,OAAO,MAAM,aAAa;AAAA,EACpD;AACA,MAAI,iBAAiB,8BAA8B;AAClD,WAAO,EAAE,MAAM,UAAU,OAAO,MAAM,aAAa;AAAA,EACpD;AACA,SAAO;AACR;AAGO,SAAS,sBAAsB,OAAgB,UAAuB;AAC5E,QAAM,SAAS,oBAAoB,OAAO,QAAQ;AAClD,QAAM,eAAe,eAAe,KAAK;AACzC,SAAO;AAAA,IACN,aAAa,QAAQ,eAAe;AAAA,IACpC,WAAW,QAAQ,aAAa;AAAA,IAChC,YAAY,QAAQ,cAAc;AAAA,IAClC,WAAW,QAAQ,aAAa;AAAA,IAChC,OAAO,QAAQ,SAAS;AAAA,IACxB,YAAY,QAAQ,cAAc;AAAA,IAClC,OAAO,eAAe,iBAAiB,KAAK,CAAC;AAAA,IAC7C,GAAI,aAAa,SAAS,eACvB,CAAC,IACD,EAAE,cAAc,eAAe,aAAa,KAAK,EAAE;AAAA,EACvD;AACD;AAEA,SAAS,uBAAuB,OAAgB,UAA+B;AAC9E,QAAM,SAAS,oBAAoB,OAAO,QAAQ;AAClD,QAAM,SAAS,SACZ;AAAA,IACA,OAAO,cAAc,OAClB,oDACA,OAAO,cAAc,kBACpB,0EACA;AAAA,IACJ,GAAI,OAAO,QAAQ,CAAC,WAAW,OAAO,KAAK,EAAE,IAAI,CAAC;AAAA,IAClD,GAAI,OAAO,aAAa,CAAC,gBAAgB,OAAO,UAAU,EAAE,IAAI,CAAC;AAAA,EAClE,IACC,CAAC;AACJ,QAAM,eAAe,eAAe,KAAK;AACzC,SAAO;AAAA,IACN,UAAKA,sBAAqB,eAAe,iBAAiB,KAAK,CAAC,CAAC,CAAC;AAAA,IAClE,GAAG;AAAA,IACH,GAAI,aAAa,SAAS,eACvB,CAAC,IACD;AAAA,MACA,mCAAmCA,sBAAqB,eAAe,aAAa,KAAK,CAAC,CAAC;AAAA,IAC5F;AAAA,EACH,EAAE,KAAK,IAAI;AACZ;AAEA,SAAS,iBAAiB,QAAoB,QAAuB;AACpE,UAAQ,IAAI,gBAAgB,QAAQ,MAAM,CAAC;AAC5C;AAEO,SAAS,sBAAsB,QAA2B;AAChE,SAAO,OAAO,cAAc,aAAa,OAAO,cAAc,iBAC3D,IACA;AACJ;AAEO,IAAM,cAAc,IAAIE,SAAQ,MAAM,EAC3C,YAAY,yDAAyD,EACrE,SAAS,iBAAiB,iBAAiB,EAC3C,eAAe,kBAAkB,oCAAoC,EACrE,OAAO,mBAAmB,wBAAwB,QAAQ,EAC1D,OAAO,aAAa,sDAAsD,EAC1E,OAAO,qBAAqB,8BAA8B,KAAK,EAC/D,aAAa,EAGb,gBAAgB,EAAE,UAAU,MAAM;AAAC,EAAE,CAAC,EACtC;AAAA,EACA,OACC,YACA,YAMI;AACJ,QAAI;AACJ,QAAI;AACH,eAAS,MAAM,QAAQ,EAAE,GAAG,SAAS,WAAW,CAAC;AACjD,UAAI,QAAQ,WAAW,QAAQ;AAC9B,gBAAQ;AAAA,UACP,KAAK;AAAA,YACJ,eAAe,QAAQ,QAAQ,WAAW,IAAI;AAAA,YAC9C;AAAA,YACA;AAAA,UACD;AAAA,QACD;AAAA,MACD,OAAO;AACN,yBAAiB,QAAQ,QAAQ,WAAW,IAAI;AAAA,MACjD;AACA,cAAQ,WAAW,sBAAsB,MAAM;AAAA,IAChD,SAAS,OAAO;AACf,UAAI,QAAQ,WAAW,QAAQ;AAC9B,gBAAQ;AAAA,UACP,KAAK,UAAU,sBAAsB,OAAO,MAAM,GAAG,MAAM,CAAC;AAAA,QAC7D;AAAA,MACD,OAAO;AACN,gBAAQ,MAAM,uBAAuB,OAAO,MAAM,CAAC;AAAA,MACpD;AACA,cAAQ,WAAW;AAAA,IACpB;AAAA,EACD;AACD;;;AC/sBD;AAAA,EACC,8BAAAC;AAAA,EACA,sBAAAC;AAAA,EACA,wBAAAC;AAAA,EACA;AAAA,EACA,wBAAAC;AAAA,EACA;AAAA,OACM;AACP,SAAS,WAAAC,gBAAe;;;ACWxB,eAAsB,WACrB,MACA,YACA,SAC8B;AAC9B,MAAI,WAAW,WAAW,GAAG;AAC5B,WAAO,EAAE,oBAAoB,GAAG,QAAQ,SAAS,UAAU,MAAM;AAAA,EAClE;AAEA,MAAI,SAAS,QAAQ;AACpB,WAAO,EAAE,oBAAoB,WAAW,QAAQ,QAAQ,KAAK;AAAA,EAC9D;AAEA,MAAI;AACJ,MAAI;AACH,aAAS,MAAM,KAAK,QAAQ;AAC5B,UAAM,OAAO,MAAM,OAAO;AAE1B,eAAW,QAAQ,YAAY;AAC9B,YAAM,OAAO,MAAM,IAAI;AAAA,IACxB;AAEA,UAAM,OAAO,MAAM,QAAQ;AAC3B,WAAO,EAAE,oBAAoB,WAAW,QAAQ,QAAQ,MAAM;AAAA,EAC/D,SAAS,OAAO;AACf,QAAI,QAAQ;AACX,YAAM,OAAO,MAAM,UAAU;AAAA,IAC9B;AACA,UAAM;AAAA,EACP,UAAE;AACD,QAAI,QAAQ;AACX,aAAO,QAAQ;AAAA,IAChB;AAAA,EACD;AACD;;;ADvCA,IAAM,mBAAmB;AAElB,IAAM,cAAc,IAAIC,SAAQ,MAAM,EAC3C,YAAY,+CAA+C,EAC3D;AAAA,EACA;AAAA,EACA;AACD,EACC,eAAe,kBAAkB,oCAAoC,EACrE,OAAO,wBAAwB,wCAAwC,EACvE,OAAO,UAAU,sDAAsD,EACvE,OAAO,aAAa,6BAA6B,EACjD,OAAO,UAAU,gBAAgB,EACjC;AAAA,EACA,OAAO,YAOD;AACL,UAAM,aAAa,QAAQ,UAAU;AACrC,UAAM,cAAc,YAAY,QAAQ,EAAE;AAE1C,QAAI,CAAC,QAAQ,MAAM;AAClB,cAAQ;AAAA,QACP,6BAAsB,UAAU,GAAG,QAAQ,OAAO,mBAAmB,EAAE;AAAA,MACxE;AACA,cAAQ,IAAI,gBAAgB,WAAW,EAAE;AACzC,UAAI,QAAQ,YAAY;AACvB,gBAAQ,IAAI,cAAc,QAAQ,UAAU,EAAE;AAAA,MAC/C;AACA,UAAI,QAAQ,QAAQ;AACnB,gBAAQ,IAAI,+CAA+C;AAAA,MAC5D;AACA,cAAQ,IAAI,EAAE;AAAA,IACf;AAEA,QAAI;AACH,YAAM,SAAS,MAAM,WAAW,UAAU;AAC1C,YAAM,cAAc,OAAO;AAE3B,YAAM,EAAE,KAAK,IAAI,MAAM,mBAAmB,QAAQ,EAAE;AAEpD,UAAI;AACH,YAAI,QAAQ,MAAM;AAEjB,gBAAM,aAAa,YAAY,aAAa;AAAA,YAC3C,uBAAuB;AAAA,YACvB,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,YAC/D,GAAI,OAAO,aAAa,SACrB,EAAE,QAAQ,2BAA2B,OAAO,QAAQ,EAAE,IACtD,CAAC;AAAA,UACL,CAAC;AAED,gBAAM,oBACL,gCAAgC,gBAAgB;AACjD,gBAAM,WAAW,WAAW;AAAA,YAC3B,CAAC,SAAS,CAAC,kBAAkB,KAAK,IAAI;AAAA,UACvC;AAEA,uBAAa,UAAU,OAAO;AAE9B,gBAAM,SAAS,MAAM,WAAW,MAAM,UAAU;AAAA,YAC/C,GAAI,QAAQ,WAAW,SACpB,EAAE,QAAQ,QAAQ,OAAO,IACzB,CAAC;AAAA,UACL,CAAC;AAED,cAAI,QAAQ,MAAM;AACjB,kBAAM,gBAAgB,WACpB,OAAO,CAAC,MAAM,gBAAgB,KAAK,CAAC,CAAC,EACrC,OAAO,CAAC,MAAM,CAAC,kBAAkB,KAAK,CAAC,CAAC,EACxC,IAAI,uBAAuB,EAC3B,OAAO,CAAC,MAAmB,MAAM,MAAS;AAC5C,oBAAQ;AAAA,cACP,KAAK;AAAA,gBACJ;AAAA,kBACC,QAAQ,QAAQ,SAAS,YAAY;AAAA,kBACrC,QAAQ;AAAA,kBACR,eAAe,cAAc;AAAA,kBAC7B,oBAAoB,OAAO;AAAA,gBAC5B;AAAA,gBACA;AAAA,gBACA;AAAA,cACD;AAAA,YACD;AAAA,UACD,WAAW,CAAC,QAAQ,QAAQ;AAC3B,oBAAQ;AAAA,cACP;AAAA,wBAAsB,OAAO,kBAAkB;AAAA,YAChD;AAAA,UACD;AAAA,QACD,OAAO;AAEN,gBAAM,UAAUC,oBAAmB,IAAI;AACvC,gBAAM,iBAAiB;AAAA,YACtB,GAAI,QAAQ,aAAa,EAAE,QAAQ,QAAQ,WAAW,IAAI,CAAC;AAAA,YAC3D,GAAI,OAAO,WAAW,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;AAAA,YACvD,qCAAqC,CACpC,YAEA,QAAQ;AAAA,cACP,kBAAQ,QAAQ,IAAI,IAAIC,sBAAqB,QAAQ,KAAK,CAAC,IAAIA,sBAAqB,QAAQ,IAAI,CAAC,KAAK,QAAQ,OAAO;AAAA,YACtH;AAAA,UACF;AACA,gBAAM,OAAO,MAAMC;AAAA,YAClB;AAAA,YACA;AAAA,YACA;AAAA,UACD;AAGA,gBAAM,aAAaC,sBAAqB,MAAM;AAAA,YAC7C,oBAAoB;AAAA,YACpB,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,UAChE,CAAC;AAGD,gBAAM,iBAAiB,KAAK,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW;AAE/D,cAAI,CAAC,QAAQ,QAAQ,eAAe,SAAS,GAAG;AAC/C,oBAAQ;AAAA,cACP,iBAAO,eAAe,MAAM;AAAA,YAC7B;AACA,uBAAW,UAAU,gBAAgB;AACpC,sBAAQ,IAAI,QAAQ,OAAO,OAAO,EAAE;AAAA,YACrC;AACA,oBAAQ,IAAI,EAAE;AAAA,UACf;AAEA,cAAI,WAAW,WAAW,GAAG;AAC5B,gBAAI,QAAQ,MAAM;AACjB,sBAAQ;AAAA,gBACP,KAAK;AAAA,kBACJ;AAAA,oBACC,QAAQ;AAAA,oBACR,oBAAoB;AAAA,oBACpB,gBAAgB,eAAe;AAAA,kBAChC;AAAA,kBACA;AAAA,kBACA;AAAA,gBACD;AAAA,cACD;AAAA,YACD,OAAO;AACN,sBAAQ,IAAI,uDAA6C;AAAA,YAC1D;AAEA;AAAA,UACD;AAEA,uBAAa,YAAY,OAAO;AAEhC,gBAAM,SAAS,MAAM,WAAW,MAAM,YAAY;AAAA,YACjD,GAAI,QAAQ,WAAW,SACpB,EAAE,QAAQ,QAAQ,OAAO,IACzB,CAAC;AAAA,UACL,CAAC;AAED,cAAI,CAAC,QAAQ,QAAQ;AACpB,kBAAM,gBAAgB,MAAMD;AAAA,cAC3B;AAAA,cACA;AAAA,cACA;AAAA,gBACC,GAAG;AAAA,gBACH,uBAAuB;AAAA,cACxB;AAAA,YACD;AACA,4CAAgC,eAAe,cAAc;AAAA,UAC9D;AAEA,cAAI,QAAQ,MAAM;AACjB,oBAAQ;AAAA,cACP,KAAK;AAAA,gBACJ;AAAA,kBACC,QAAQ,QAAQ,SAAS,YAAY;AAAA,kBACrC,oBAAoB,OAAO;AAAA,kBAC3B,gBAAgB,eAAe;AAAA,gBAChC;AAAA,gBACA;AAAA,gBACA;AAAA,cACD;AAAA,YACD;AAAA,UACD,WAAW,CAAC,QAAQ,QAAQ;AAC3B,oBAAQ;AAAA,cACP;AAAA,wBAAsB,OAAO,kBAAkB;AAAA,YAChD;AAAA,UACD;AAAA,QACD;AAAA,MAED,UAAE;AACD,cAAM,KAAK,IAAI;AAAA,MAChB;AAAA,IACD,SAAS,OAAO;AACf,YAAM,UACL,iBAAiB,QAAQ,MAAM,UAAU;AAE1C,UAAI,QAAQ,MAAM;AACjB,gBAAQ;AAAA,UACP,KAAK,UAAU,EAAE,QAAQ,SAAS,OAAO,QAAQ,GAAG,MAAM,CAAC;AAAA,QAC5D;AAAA,MACD,OAAO;AACN,gBAAQ,MAAM,iBAAY,OAAO,EAAE;AAAA,MACpC;AACA,cAAQ,KAAK,CAAC;AAAA,IACf;AAAA,EACD;AACD;AAkBM,SAAS,gCAAgC,WAA2B;AAC1E,QAAM,UAAU,UAAU,QAAQ,wBAAwB,MAAM;AAChE,SAAO,IAAI;AAAA,IACV,iEAAiE,OAAO;AAAA,IACxE;AAAA,EACD;AACD;AAUO,SAAS,wBAAwB,WAA2B;AAClE,QAAM,QAAQ,UAAU,MAAM,qCAAqC;AACnE,SAAO,QAAQ,CAAC,KAAK;AACtB;AAEA,SAAS,aACR,YACA,SACO;AACP,MAAI,QAAQ,UAAU,CAAC,QAAQ,MAAM;AACpC,YAAQ,IAAI,eAAe,WAAW,MAAM;AAAA,CAAiB;AAC7D,eAAW,QAAQ,YAAY;AAC9B,cAAQ,IAAI,GAAG,IAAI;AAAA,CAAK;AAAA,IACzB;AAAA,EACD;AACD;AAEA,SAAS,gCACR,eACA,gBACO;AACP,QAAM,cAAc,IAAI,IAAI,eAAe,IAAI,cAAc,CAAC;AAC9D,QAAM,aAAa,cAAc,QAAQ;AAAA,IACxC,CAAC,WACA,EAAE,OAAO,eAAe,YAAY,IAAI,eAAe,MAAM,CAAC;AAAA,EAChE;AACA,MAAI,WAAW,WAAW,EAAG;AAE7B,QAAM,IAAI;AAAA,IACT,6CAA6C,WAAW,MAAM;AAAA,IAC7D,WAAW,IAAI,uBAAuB,EAAE,KAAK,IAAI;AAAA,EACnD;AACD;AAEA,SAAS,eAAe,QAA8B;AACrD,SAAO,KAAK,UAAU;AAAA,IACrB,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO,UAAU;AAAA,IACjB,OAAO;AAAA,IACP,OAAO;AAAA,EACR,CAAC;AACF;AAEA,SAAS,wBAAwB,QAA8B;AAC9D,QAAM,SAAS,OAAO,SACnB,GAAG,OAAO,KAAK,IAAI,OAAO,MAAM,KAChC,OAAO,SAAS;AACnB,SAAO,QAAQ,OAAO,OAAO,KAAK,OAAO,IAAI,KAAK,MAAM;AACzD;;;AEtTA,SAAS,gBAAAE,qBAAoB;AAE7B,SAAS,WAAAC,gBAAe;AA+BjB,IAAM,cAAc,IAAIC,SAAQ,MAAM,EAC3C,YAAY,0DAA0D,EACtE,OAAO,uBAAuB,4CAA4C,EAC1E;AAAA,EACA;AAAA,EACA;AACD,EACC,OAAO,sBAAsB,8CAA8C,EAC3E;AAAA,EACA;AAAA,EACA;AACD,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,EACC;AAAA,EACA;AAAA,EACA;AACD,EACC;AAAA,EACA;AAAA,EACA;AACD,EACC;AAAA,EACA;AAAA,EACA;AACD,EACC,OAAO,WAAW,oDAAoD,EACtE,OAAO,UAAU,kDAAkD,EACnE;AAAA,EACA;AAAA,EACA;AACD,EACC;AAAA,EACA;AAAA,EACA;AACD,EACC,OAAO,OAAO,YAAyB;AAEvC,MAAI,QAAQ,QAAQ;AACnB,WAAO,cAAc,QAAQ,MAAM;AAAA,EACpC;AAEA,SAAO,KAAK;AACZ,MAAI;AAEH,QAAI;AACJ,QAAI;AAEJ,QAAI,QAAQ,QAAQ;AACnB,eAAS,MAAM,WAAW,QAAQ,MAAM;AACxC,mBAAa,QAAQ;AAAA,IACtB,OAAO;AACN,YAAM,SAAS,MAAM,kBAAkB;AACvC,eAAS,OAAO;AAChB,mBAAa,OAAO;AAAA,IACrB;AAGA,QAAI,QAAQ,UAAU,CAAC,QAAQ,OAAO;AACrC,YAAM,IAAI;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAIA,QAAI,QAAQ,UAAU,CAAC,QAAQ,QAAQ,CAAC,QAAQ,OAAO;AACtD,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACnE;AAKA,QAAI,QAAQ,KAAK;AAChB,yBAAmB,QAAQ,KAAK,QAAQ;AAAA,IACzC;AAGA,UAAM,WAAW,oBAAoB,QAAQ,MAAM,KAAK,OAAO;AAG/D,QAAI,QAAQ,QAAQ,QAAQ,OAAO;AAClC,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,iBAAkB;AACxD,YAAM,UAAoB,CAAC;AAG3B,UAAI,QAAQ,KAAK;AAChB,gBAAQ,KAAK,QAAQ,QAAQ,GAAG,EAAE;AAAA,MACnC;AAGA,UAAI,QAAQ,QAAQ;AACnB,mBAAW,QAAQ,QAAQ,QAAQ;AAClC,kBAAQ,KAAK,WAAW,IAAI,EAAE;AAAA,QAC/B;AAAA,MACD;AAEA,UAAI,QAAQ,MAAM;AACjB,gBAAQ,KAAK,QAAQ,IAAI;AAAA,MAC1B;AAEA,UAAI,QAAQ,OAAO;AAElB,YAAI;AACJ,YAAI;AACH,oBAAUC,cAAa,QAAQ,OAAO,OAAO;AAAA,QAC9C,SAAS,KAAK;AACb,gBAAM,aACL,eAAe,SACf,UAAU,OACT,IAA8B,SAAS;AACzC,gBAAM,IAAI;AAAA,YACT,aACG,yBAAyB,QAAQ,KAAK,KACtC,8BAA8B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,UAClF;AAAA,QACD;AACA,gBAAQ,KAAK,GAAG,QAAQ,MAAM,IAAI,CAAC;AAAA,MACpC;AAEA,YAAM,aAAa;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,QAAQ,UAAU;AAAA,QAC1B,GAAI,QAAQ,MAAM,EAAE,aAAa,QAAQ,GAAG;AAAA,QAC5C,GAAI,QAAQ,UAAU,EAAE,YAAY,QAAQ,OAAO;AAAA,QACnD,GAAI,YAAY,EAAE,SAAS;AAAA,MAC5B,CAAC;AACD;AAAA,IACD;AAGA,UAAM,EAAE,UAAU,IAAI,MAAM,OAAO,oBAAkB;AAGrD,UAAM,UAAU;AAAA,MACf;AAAA,MACA;AAAA,MACA,GAAI,QAAQ,MAAM,EAAE,aAAa,QAAQ,GAAG;AAAA,MAC5C,GAAI,QAAQ,OAAO,EAAE,mBAAmB,QAAQ,IAAI;AAAA,MACpD,GAAI,QAAQ,SAAS,EAAE,kBAAkB,KAAK;AAAA,MAC9C,GAAI,QAAQ,QAAQ,EAAE,iBAAiB,KAAK;AAAA,MAC5C,GAAI,YAAY,EAAE,SAAS;AAAA,IAC5B,CAAC;AAAA,EACF,SAAS,OAAO;AACf,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAQ,MAAM,UAAK,OAAO,EAAE;AAC5B,YAAQ,KAAK,CAAC;AAAA,EACf;AACD,CAAC;AAEF,SAAS,oBACR,QACuB;AACvB,UAAQ,QAAQ;AAAA,IACf,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR;AACC,aAAO;AAAA,EACT;AACD;;;ACzMA;AAAA,EACC,8BAAAC;AAAA,EACA,sBAAAC;AAAA,EACA,wBAAAC;AAAA,OACM;AACP,SAAS,WAAAC,gBAAe;;;AC6ExB,IAAM,kBAGF;AAAA,EACH,cAAc,EAAE,MAAM,uBAAuB,UAAU,QAAQ;AAAA,EAC/D,YAAY,EAAE,MAAM,2BAA2B,UAAU,UAAU;AAAA,EACnE,YAAY,EAAE,MAAM,wBAAwB,UAAU,QAAQ;AAAA,EAC9D,aAAa,EAAE,MAAM,4BAA4B,UAAU,OAAO;AAAA,EAClE,mBAAmB,EAAE,MAAM,iBAAiB,UAAU,QAAQ;AAAA,EAC9D,uBAAuB,EAAE,MAAM,qBAAqB,UAAU,UAAU;AAAA,EACxE,sBAAsB,EAAE,MAAM,oBAAoB,UAAU,UAAU;AAAA,EACtE,qBAAqB,EAAE,MAAM,mBAAmB,UAAU,UAAU;AAAA,EACpE,iBAAiB,EAAE,MAAM,wBAAwB,UAAU,QAAQ;AAAA,EACnE,kBAAkB,EAAE,MAAM,wBAAwB,UAAU,QAAQ;AAAA,EACpE,iBAAiB,EAAE,MAAM,oBAAoB,UAAU,QAAQ;AAAA,EAC/D,kBAAkB,EAAE,MAAM,wBAAwB,UAAU,UAAU;AAAA,EACtE,mBAAmB,EAAE,MAAM,yBAAyB,UAAU,UAAU;AAAA,EACxE,cAAc,EAAE,MAAM,uBAAuB,UAAU,UAAU;AAAA,EACjE,YAAY,EAAE,MAAM,2BAA2B,UAAU,OAAO;AAAA;AAAA,EAEhE,sBAAsB,EAAE,MAAM,uBAAuB,UAAU,UAAU;AAAA,EACzE,uBAAuB,EAAE,MAAM,2BAA2B,UAAU,OAAO;AAAA;AAAA,EAE3E,aAAa,EAAE,MAAM,sBAAsB,UAAU,QAAQ;AAAA,EAC7D,sBAAsB,EAAE,MAAM,uBAAuB,UAAU,UAAU;AAAA,EACzE,WAAW,EAAE,MAAM,0BAA0B,UAAU,UAAU;AAAA;AAAA,EAEjE,wBAAwB,EAAE,MAAM,sBAAsB,UAAU,UAAU;AAAA,EAC1E,uBAAuB,EAAE,MAAM,qBAAqB,UAAU,UAAU;AAAA;AAAA,EAExE,aAAa,EAAE,MAAM,oBAAoB,UAAU,OAAO;AAAA,EAC1D,cAAc,EAAE,MAAM,oBAAoB,UAAU,OAAO;AAAA;AAAA,EAE3D,kBAAkB,EAAE,MAAM,qBAAqB,UAAU,QAAQ;AAAA,EACjE,gBAAgB,EAAE,MAAM,qBAAqB,UAAU,OAAO;AAAA,EAC9D,iBAAiB,EAAE,MAAM,oBAAoB,UAAU,UAAU;AAAA,EACjE,gBAAgB,EAAE,MAAM,qBAAqB,UAAU,UAAU;AAAA,EACjE,eAAe,EAAE,MAAM,oBAAoB,UAAU,OAAO;AAAA;AAAA,EAE5D,qBAAqB;AAAA,IACpB,MAAM;AAAA,IACN,UAAU;AAAA,EACX;AAAA;AAAA,EAEA,YAAY,EAAE,MAAM,wBAAwB,UAAU,UAAU;AAAA,EAChE,aAAa,EAAE,MAAM,wBAAwB,UAAU,UAAU;AAAA,EACjE,eAAe,EAAE,MAAM,wBAAwB,UAAU,UAAU;AAAA,EACnE,aAAa,EAAE,MAAM,4BAA4B,UAAU,UAAU;AACtE;AAEA,SAAS,mBAAmB,QAAkC;AAC7D,QAAM,UAAU,gBAAgB,OAAO,IAAI,KAAK;AAAA,IAC/C,MAAM;AAAA,IACN,UAAU;AAAA,EACX;AACA,SAAO;AAAA,IACN,UAAU,QAAQ;AAAA,IAClB,MAAM,QAAQ;AAAA,IACd,OAAO,OAAO;AAAA,IACd,GAAI,OAAO,WAAW,SAAY,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,IAC/D,SAAS,OAAO;AAAA,EACjB;AACD;AAaO,SAAS,eACf,MACA,cACA,UACe;AACf,QAAM,SAAS,KAAK,QAAQ,IAAI,kBAAkB;AAGlD,QAAM,gBAA+C;AAAA,IACpD,OAAO;AAAA,IACP,SAAS;AAAA,IACT,MAAM;AAAA,EACP;AACA,SAAO;AAAA,IACN,CAAC,GAAe,MACf,cAAc,EAAE,QAAQ,IAAI,cAAc,EAAE,QAAQ;AAAA,EACtD;AAEA,QAAM,YAAY,OAAO,KAAK,CAAC,MAAkB,EAAE,aAAa,OAAO;AAEvE,SAAO;AAAA,IACN,OAAO,CAAC;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;AASO,SAAS,mBAAmB,QAA8B;AAChE,QAAM,QAAkB,CAAC;AAEzB,MAAI,OAAO,OAAO;AACjB,UAAM,KAAK,gCAA2B;AAAA,EACvC,OAAO;AACN,UAAM,KAAK,8BAAyB;AAAA,EACrC;AAEA,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,qBAAqB,OAAO,aAAa,MAAM,EAAE;AAC5D,QAAM,KAAK,uBAAuB,OAAO,SAAS,MAAM,EAAE;AAC1D,QAAM,KAAK,EAAE;AAEb,MAAI,OAAO,OAAO,WAAW,GAAG;AAC/B,UAAM,KAAK,kBAAkB;AAAA,EAC9B,OAAO;AACN,UAAM,SAAS,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO;AACjE,UAAM,WAAW,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,SAAS;AACrE,UAAM,QAAQ,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,MAAM;AAE/D,QAAI,OAAO,SAAS,GAAG;AACtB,YAAM,KAAK,UAAK,OAAO,MAAM,YAAY;AACzC,iBAAW,SAAS,QAAQ;AAC3B,cAAM,KAAK,MAAM,MAAM,OAAO,EAAE;AAAA,MACjC;AACA,YAAM,KAAK,EAAE;AAAA,IACd;AAEA,QAAI,SAAS,SAAS,GAAG;AACxB,YAAM,KAAK,iBAAO,SAAS,MAAM,cAAc;AAC/C,iBAAW,SAAS,UAAU;AAC7B,cAAM,KAAK,MAAM,MAAM,OAAO,EAAE;AAAA,MACjC;AACA,YAAM,KAAK,EAAE;AAAA,IACd;AAEA,QAAI,MAAM,SAAS,GAAG;AACrB,YAAM,KAAK,iBAAO,MAAM,MAAM,QAAQ;AACtC,iBAAW,SAAS,OAAO;AAC1B,cAAM,KAAK,MAAM,MAAM,OAAO,EAAE;AAAA,MACjC;AACA,YAAM,KAAK,EAAE;AAAA,IACd;AAAA,EACD;AAEA,SAAO,MAAM,KAAK,IAAI;AACvB;;;ADtOO,IAAM,gBAAgB,IAAIC,SAAQ,QAAQ,EAC/C,YAAY,mDAAmD,EAC/D;AAAA,EACA;AAAA,EACA;AACD,EACC,eAAe,kBAAkB,oCAAoC,EACrE,OAAO,wBAAwB,wCAAwC,EACvE,OAAO,UAAU,gBAAgB,EACjC;AAAA,EACA,OAAO,YAKD;AACL,UAAM,aAAa,QAAQ,UAAU;AAErC,UAAM,cAAc,YAAY,QAAQ,EAAE;AAE1C,QAAI,CAAC,QAAQ,MAAM;AAClB,cAAQ,IAAI,+BAAwB,UAAU,EAAE;AAChD,cAAQ,IAAI,gBAAgB,WAAW,EAAE;AACzC,UAAI,QAAQ,YAAY;AACvB,gBAAQ,IAAI,cAAc,QAAQ,UAAU,EAAE;AAAA,MAC/C;AACA,cAAQ,IAAI,EAAE;AAAA,IACf;AAEA,QAAI;AAEH,YAAM,SAAS,MAAM,WAAW,UAAU;AAC1C,YAAM,cAAc,OAAO;AAG3B,YAAM,EAAE,KAAK,IAAI,MAAM,mBAAmB,QAAQ,EAAE;AAEpD,UAAI;AACH,cAAM,UAAUC,oBAAmB,IAAI;AAGvC,cAAM,OAAO,MAAMC,4BAA2B,SAAS,aAAa;AAAA,UACnE,GAAI,QAAQ,aAAa,EAAE,QAAQ,QAAQ,WAAW,IAAI,CAAC;AAAA,UAC3D,GAAI,OAAO,aAAa,SACrB,EAAE,UAAU,OAAO,SAAS,IAC5B,CAAC;AAAA,UACJ,qCAAqC,CAAC,YACrC,QAAQ;AAAA,YACP,kBAAQ,QAAQ,IAAI,IAAIC,sBAAqB,QAAQ,KAAK,CAAC,IAAIA,sBAAqB,QAAQ,IAAI,CAAC,KAAK,QAAQ,OAAO;AAAA,UACtH;AAAA,QACF,CAAC;AAKD,cAAM,UAAU,MAAM,QAAQ,WAAW;AAAA,UACxC,GAAI,QAAQ,aAAa,EAAE,QAAQ,QAAQ,WAAW,IAAI,CAAC;AAAA,QAC5D,CAAC;AACD,cAAM,eAAe,MAAM,KAAK,YAAY,OAAO,KAAK,CAAC;AACzD,cAAM,WAAW,MAAM,KAAK,QAAQ,OAAO,KAAK,CAAC;AACjD,cAAM,SAAS,eAAe,MAAM,cAAc,QAAQ;AAG1D,YAAI,QAAQ,MAAM;AAEjB,gBAAM,EAAE,MAAM,OAAO,GAAG,WAAW,IAAI;AACvC,kBAAQ;AAAA,YACP,KAAK;AAAA,cACJ;AAAA,gBACC,GAAG;AAAA,gBACH,SAAS,KAAK;AAAA,gBACd,gBAAgB,KAAK;AAAA,cACtB;AAAA,cACA;AAAA,cACA;AAAA,YACD;AAAA,UACD;AAAA,QACD,OAAO;AACN,kBAAQ,IAAI,mBAAmB,MAAM,CAAC;AAAA,QACvC;AAGA,gBAAQ,WAAW,OAAO,QAAQ,IAAI;AACtC;AAAA,MACD,UAAE;AAED,cAAM,KAAK,IAAI;AAAA,MAChB;AAAA,IACD,SAAS,OAAO;AACf,YAAM,UACL,iBAAiB,QAAQ,MAAM,UAAU;AAE1C,UAAI,QAAQ,MAAM;AACjB,gBAAQ;AAAA,UACP,KAAK,UAAU,EAAE,QAAQ,SAAS,OAAO,QAAQ,GAAG,MAAM,CAAC;AAAA,QAC5D;AAAA,MACD,OAAO;AACN,gBAAQ,MAAM,iBAAY,OAAO,EAAE;AAAA,MACpC;AACA,cAAQ,KAAK,CAAC;AAAA,IACf;AAAA,EACD;AACD;;;ATvGD,IAAM,UAAU,IAAIC,SAAQ;AAE5B,SAAS,gBACR,MACA,UACoE;AACpE,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACpD,UAAM,WAAW,KAAK,KAAK;AAC3B,QAAI,aAAa,KAAM,QAAO;AAC9B,QAAI,UAAU,WAAW,GAAG,EAAG;AAC/B,UAAM,UAAU,SAAS,KAAK,CAAC,cAAc,UAAU,KAAK,MAAM,QAAQ;AAC1E,WAAO,YAAY,SAAY,SAAY,EAAE,SAAS,MAAM;AAAA,EAC7D;AACA,SAAO;AACR;AAEA,SAAS,iBACR,MACA,UACU;AACV,QAAM,WAAW,gBAAgB,MAAM,QAAQ;AAC/C,MAAI,UAAU,YAAY,YAAa,QAAO;AAE9C,WAAS,QAAQ,SAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACrE,UAAM,WAAW,KAAK,KAAK;AAC3B,QAAI,aAAa,KAAM;AACvB,QACE,aAAa,cAAc,KAAK,QAAQ,CAAC,MAAM,UAChD,aAAa,iBACZ;AACD,aAAO;AAAA,IACR;AAAA,EACD;AACA,SAAO;AACR;AAEA,QACE,KAAK,MAAM,EACX,YAAY,sDAAsD,EAClE,QAAQ,OAAO;AAGjB,QAAQ,WAAW,eAAe;AAClC,QAAQ,WAAW,iBAAiB;AACpC,QAAQ,WAAW,cAAc;AACjC,QAAQ,WAAW,WAAW;AAC9B,QAAQ,WAAW,WAAW;AAC9B,QAAQ,WAAW,WAAW;AAC9B,QAAQ,WAAW,aAAa;AAEhC,IAAM,oBAAoB;AAAA,EACzB,QAAQ,KAAK,MAAM,CAAC;AAAA,EACpB,QAAQ;AACT;AAKA,IAAI,mBAAmB;AACtB,UAAQ,gBAAgB,EAAE,UAAU,MAAM;AAAA,EAAC,EAAE,CAAC;AAC/C;AAIA,QAAQ,aAAa;AAErB,IAAI;AACH,UAAQ,MAAM;AACf,SAAS,KAAK;AAGb,MAAI,eAAe,kBAAkB,IAAI,aAAa,GAAG;AACxD,YAAQ,KAAK,CAAC;AAAA,EACf;AACA,QAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,MAAI,QAAQ,KAAK,SAAS,QAAQ,KAAK,mBAAmB;AACzD,YAAQ,IAAI,KAAK,UAAU,EAAE,QAAQ,SAAS,OAAO,QAAQ,GAAG,MAAM,CAAC,CAAC;AAAA,EACzE,OAAO;AACN,YAAQ,MAAM,UAAK,OAAO,EAAE;AAAA,EAC7B;AACA,UAAQ,KAAK,CAAC;AACf;","names":["Command","outputPath","mkdirSync","writeFileSync","dirname","resolve","Command","Command","resolve","mkdirSync","dirname","writeFileSync","Command","mkdirSync","writeFileSync","resolve","Command","createPgsqlAdapter","escapeDiagnosticText","Command","escapeDiagnosticText","createPgsqlAdapter","Command","comparePgsqlDatabaseSchema","createPgsqlAdapter","escapeDiagnosticText","generateMigrationSQL","Command","Command","createPgsqlAdapter","escapeDiagnosticText","comparePgsqlDatabaseSchema","generateMigrationSQL","readFileSync","Command","Command","readFileSync","comparePgsqlDatabaseSchema","createPgsqlAdapter","escapeDiagnosticText","Command","Command","createPgsqlAdapter","comparePgsqlDatabaseSchema","escapeDiagnosticText","Command"]}
|