@digilogiclabs/platform-core 1.1.1 → 1.3.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/postgres/PostgresDatabase.ts","../src/migrations/Migrator.ts","../src/migrations/cli.ts"],"sourcesContent":["/**\n * PostgreSQL Direct Database Adapter\n *\n * Production implementation using pg (node-postgres) for direct PostgreSQL connections.\n * Provides true ACID transaction support, connection pooling, and prepared statements.\n *\n * This adapter is vendor-agnostic - works with any PostgreSQL-compatible database:\n * - PostgreSQL (self-hosted or managed)\n * - Amazon RDS PostgreSQL\n * - Azure Database for PostgreSQL\n * - Google Cloud SQL for PostgreSQL\n * - CockroachDB (PostgreSQL wire protocol)\n * - YugabyteDB\n * - Neon, Supabase (direct connection, not REST)\n */\n\nimport type {\n Pool,\n PoolClient,\n PoolConfig,\n QueryResult as PgQueryResult,\n} from \"pg\";\nimport {\n IDatabase,\n IQueryBuilder,\n QueryResult,\n} from \"../../interfaces/IDatabase\";\n\nexport interface PostgresConfig {\n /** Connection string (postgresql://user:pass@host:port/database) */\n connectionString?: string;\n\n /** Host name */\n host?: string;\n\n /** Port number */\n port?: number;\n\n /** Database name */\n database?: string;\n\n /** Username */\n user?: string;\n\n /** Password */\n password?: string;\n\n /** SSL configuration */\n ssl?: boolean | { rejectUnauthorized?: boolean; ca?: string };\n\n /** Maximum number of connections in pool */\n max?: number;\n\n /** Idle timeout in milliseconds */\n idleTimeoutMillis?: number;\n\n /** Connection timeout in milliseconds */\n connectionTimeoutMillis?: number;\n\n /** Statement timeout in milliseconds (0 = no limit) */\n statementTimeout?: number;\n\n /** Query timeout in milliseconds (0 = no limit) */\n queryTimeout?: number;\n\n /** Application name for connection identification */\n applicationName?: string;\n}\n\n/**\n * Convert our config to pg pool config\n */\nfunction toPoolConfig(config: PostgresConfig): PoolConfig {\n const poolConfig: PoolConfig = {};\n\n if (config.connectionString) {\n poolConfig.connectionString = config.connectionString;\n } else {\n poolConfig.host = config.host;\n poolConfig.port = config.port;\n poolConfig.database = config.database;\n poolConfig.user = config.user;\n poolConfig.password = config.password;\n }\n\n if (config.ssl !== undefined) {\n poolConfig.ssl = config.ssl;\n }\n\n poolConfig.max = config.max ?? 10;\n poolConfig.idleTimeoutMillis = config.idleTimeoutMillis ?? 30000;\n poolConfig.connectionTimeoutMillis = config.connectionTimeoutMillis ?? 10000;\n poolConfig.application_name = config.applicationName ?? \"platform-core\";\n\n // Statement timeout\n if (config.statementTimeout) {\n poolConfig.statement_timeout = config.statementTimeout;\n }\n\n // Query timeout\n if (config.queryTimeout) {\n poolConfig.query_timeout = config.queryTimeout;\n }\n\n return poolConfig;\n}\n\nexport class PostgresDatabase implements IDatabase {\n private pool: Pool;\n private config: PostgresConfig;\n\n constructor(pool: Pool, config: PostgresConfig = {}) {\n this.pool = pool;\n this.config = config;\n }\n\n /**\n * Create a PostgresDatabase from configuration\n */\n static async create(config: PostgresConfig): Promise<PostgresDatabase> {\n // Dynamic import to keep pg as optional peer dependency\n const { Pool } = await import(\"pg\");\n const poolConfig = toPoolConfig(config);\n const pool = new Pool(poolConfig);\n\n // Test connection\n const client = await pool.connect();\n client.release();\n\n return new PostgresDatabase(pool, config);\n }\n\n /**\n * Create from environment variables\n */\n static async fromEnv(): Promise<PostgresDatabase> {\n const config: PostgresConfig = {\n connectionString: process.env.DATABASE_URL,\n host: process.env.POSTGRES_HOST ?? process.env.PGHOST,\n port: parseInt(\n process.env.POSTGRES_PORT ?? process.env.PGPORT ?? \"5432\",\n 10,\n ),\n database: process.env.POSTGRES_DATABASE ?? process.env.PGDATABASE,\n user: process.env.POSTGRES_USER ?? process.env.PGUSER,\n password: process.env.POSTGRES_PASSWORD ?? process.env.PGPASSWORD,\n max: parseInt(process.env.POSTGRES_POOL_MAX ?? \"10\", 10),\n ssl:\n process.env.POSTGRES_SSL === \"true\"\n ? {\n rejectUnauthorized:\n process.env.POSTGRES_SSL_REJECT_UNAUTHORIZED !== \"false\",\n }\n : undefined,\n applicationName: process.env.POSTGRES_APP_NAME ?? \"platform-core\",\n };\n\n return PostgresDatabase.create(config);\n }\n\n from<T = unknown>(table: string): IQueryBuilder<T> {\n return new PostgresQueryBuilder<T>(this.pool, table);\n }\n\n async raw<T = unknown>(\n sql: string,\n params?: unknown[],\n ): Promise<QueryResult<T>> {\n try {\n const result: PgQueryResult = await this.pool.query(sql, params);\n return {\n data: result.rows as T[],\n count: result.rowCount ?? undefined,\n };\n } catch (error) {\n return {\n data: [],\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n }\n\n /**\n * Execute a function within a database transaction.\n * Provides true ACID guarantees - either all operations succeed or all are rolled back.\n */\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\n const client = await this.pool.connect();\n\n try {\n await client.query(\"BEGIN\");\n\n // Create a transaction-scoped database instance\n const txDatabase = new TransactionDatabase(client);\n\n const result = await fn(txDatabase);\n\n await client.query(\"COMMIT\");\n return result;\n } catch (error) {\n await client.query(\"ROLLBACK\");\n throw error;\n } finally {\n client.release();\n }\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n const result = await this.pool.query(\"SELECT 1 as health\");\n return result.rows.length > 0;\n } catch {\n return false;\n }\n }\n\n async close(): Promise<void> {\n await this.pool.end();\n }\n\n /**\n * Get pool statistics for monitoring\n */\n getPoolStats(): {\n totalCount: number;\n idleCount: number;\n waitingCount: number;\n } {\n return {\n totalCount: this.pool.totalCount,\n idleCount: this.pool.idleCount,\n waitingCount: this.pool.waitingCount,\n };\n }\n}\n\n/**\n * Transaction-scoped database that uses a single client connection\n */\nclass TransactionDatabase implements IDatabase {\n constructor(private client: PoolClient) {}\n\n from<T = unknown>(table: string): IQueryBuilder<T> {\n return new PostgresQueryBuilder<T>(this.client, table);\n }\n\n async raw<T = unknown>(\n sql: string,\n params?: unknown[],\n ): Promise<QueryResult<T>> {\n try {\n const result = await this.client.query(sql, params);\n return {\n data: result.rows as T[],\n count: result.rowCount ?? undefined,\n };\n } catch (error) {\n return {\n data: [],\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n }\n\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\n // Nested transaction using savepoint\n const savepointName = `sp_${Date.now()}_${Math.random().toString(36).slice(2)}`;\n\n try {\n await this.client.query(`SAVEPOINT ${savepointName}`);\n const result = await fn(this);\n await this.client.query(`RELEASE SAVEPOINT ${savepointName}`);\n return result;\n } catch (error) {\n await this.client.query(`ROLLBACK TO SAVEPOINT ${savepointName}`);\n throw error;\n }\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n await this.client.query(\"SELECT 1\");\n return true;\n } catch {\n return false;\n }\n }\n\n async close(): Promise<void> {\n // Transaction database doesn't own the client, so don't close\n }\n}\n\n/**\n * PostgreSQL Query Builder\n */\nclass PostgresQueryBuilder<T = unknown> implements IQueryBuilder<T> {\n private client: Pool | PoolClient;\n private tableName: string;\n private _select: string[] = [\"*\"];\n private _where: Array<{ column: string; operator: string; value: unknown }> =\n [];\n private _whereIn: Array<{ column: string; values: unknown[] }> = [];\n private _orderBy: { column: string; direction: \"asc\" | \"desc\" } | null = null;\n private _limit: number | null = null;\n private _offset: number = 0;\n private _insertData: Partial<T>[] | null = null;\n private _updateData: Partial<T> | null = null;\n private _deleteFlag: boolean = false;\n private _returning: string[] = [\"*\"];\n\n constructor(client: Pool | PoolClient, tableName: string) {\n this.client = client;\n this.tableName = this.escapeIdentifier(tableName);\n }\n\n select(columns?: string | string[]): IQueryBuilder<T> {\n if (columns) {\n this._select = Array.isArray(columns) ? columns : [columns];\n }\n return this;\n }\n\n insert(data: Partial<T> | Partial<T>[]): IQueryBuilder<T> {\n this._insertData = Array.isArray(data) ? data : [data];\n return this;\n }\n\n update(data: Partial<T>): IQueryBuilder<T> {\n this._updateData = data;\n return this;\n }\n\n delete(): IQueryBuilder<T> {\n this._deleteFlag = true;\n return this;\n }\n\n where(column: string, operator: string, value: unknown): IQueryBuilder<T> {\n this._where.push({ column, operator, value });\n return this;\n }\n\n whereIn(column: string, values: unknown[]): IQueryBuilder<T> {\n this._whereIn.push({ column, values });\n return this;\n }\n\n orderBy(column: string, direction: \"asc\" | \"desc\" = \"asc\"): IQueryBuilder<T> {\n this._orderBy = { column, direction };\n return this;\n }\n\n limit(count: number): IQueryBuilder<T> {\n this._limit = count;\n return this;\n }\n\n offset(count: number): IQueryBuilder<T> {\n this._offset = count;\n return this;\n }\n\n async single(): Promise<{ data: T | null; error?: Error }> {\n this._limit = 1;\n const result = await this.execute();\n\n if (result.error) {\n return { data: null, error: result.error };\n }\n\n return { data: result.data[0] ?? null };\n }\n\n async execute(): Promise<QueryResult<T>> {\n try {\n if (this._insertData) {\n return await this.executeInsert();\n }\n\n if (this._updateData) {\n return await this.executeUpdate();\n }\n\n if (this._deleteFlag) {\n return await this.executeDelete();\n }\n\n return await this.executeSelect();\n } catch (error) {\n return {\n data: [],\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n }\n\n private async executeSelect(): Promise<QueryResult<T>> {\n const params: unknown[] = [];\n let paramIndex = 1;\n\n // Build SELECT clause\n const selectClause = this._select\n .map((col) => this.escapeIdentifier(col))\n .join(\", \");\n let sql = `SELECT ${selectClause} FROM ${this.tableName}`;\n\n // Build WHERE clause\n const whereClauses: string[] = [];\n\n for (const { column, operator, value } of this._where) {\n whereClauses.push(\n `${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`,\n );\n params.push(value);\n }\n\n for (const { column, values } of this._whereIn) {\n const placeholders = values.map(() => `$${paramIndex++}`).join(\", \");\n whereClauses.push(\n `${this.escapeIdentifier(column)} IN (${placeholders})`,\n );\n params.push(...values);\n }\n\n if (whereClauses.length > 0) {\n sql += ` WHERE ${whereClauses.join(\" AND \")}`;\n }\n\n // Build ORDER BY\n if (this._orderBy) {\n sql += ` ORDER BY ${this.escapeIdentifier(this._orderBy.column)} ${this._orderBy.direction.toUpperCase()}`;\n }\n\n // Build LIMIT and OFFSET\n if (this._limit !== null) {\n sql += ` LIMIT $${paramIndex++}`;\n params.push(this._limit);\n }\n\n if (this._offset > 0) {\n sql += ` OFFSET $${paramIndex++}`;\n params.push(this._offset);\n }\n\n const result = await this.client.query(sql, params);\n return {\n data: result.rows as T[],\n count: result.rowCount ?? undefined,\n };\n }\n\n private async executeInsert(): Promise<QueryResult<T>> {\n if (!this._insertData || this._insertData.length === 0) {\n return { data: [] };\n }\n\n const params: unknown[] = [];\n let paramIndex = 1;\n\n // Get all unique columns from the data\n const columns = new Set<string>();\n for (const row of this._insertData) {\n Object.keys(row as object).forEach((key) => columns.add(key));\n }\n const columnList = Array.from(columns);\n\n // Build column list\n const columnClause = columnList\n .map((col) => this.escapeIdentifier(col))\n .join(\", \");\n\n // Build values\n const valueRows: string[] = [];\n for (const row of this._insertData) {\n const rowValues: string[] = [];\n for (const col of columnList) {\n rowValues.push(`$${paramIndex++}`);\n params.push((row as Record<string, unknown>)[col] ?? null);\n }\n valueRows.push(`(${rowValues.join(\", \")})`);\n }\n\n const sql = `INSERT INTO ${this.tableName} (${columnClause}) VALUES ${valueRows.join(\", \")} RETURNING ${this._returning.join(\", \")}`;\n\n const result = await this.client.query(sql, params);\n return {\n data: result.rows as T[],\n count: result.rowCount ?? undefined,\n };\n }\n\n private async executeUpdate(): Promise<QueryResult<T>> {\n if (!this._updateData) {\n return { data: [] };\n }\n\n const params: unknown[] = [];\n let paramIndex = 1;\n\n // Build SET clause\n const setClauses: string[] = [];\n for (const [key, value] of Object.entries(this._updateData as object)) {\n setClauses.push(`${this.escapeIdentifier(key)} = $${paramIndex++}`);\n params.push(value);\n }\n\n let sql = `UPDATE ${this.tableName} SET ${setClauses.join(\", \")}`;\n\n // Build WHERE clause\n const whereClauses: string[] = [];\n\n for (const { column, operator, value } of this._where) {\n whereClauses.push(\n `${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`,\n );\n params.push(value);\n }\n\n for (const { column, values } of this._whereIn) {\n const placeholders = values.map(() => `$${paramIndex++}`).join(\", \");\n whereClauses.push(\n `${this.escapeIdentifier(column)} IN (${placeholders})`,\n );\n params.push(...values);\n }\n\n if (whereClauses.length > 0) {\n sql += ` WHERE ${whereClauses.join(\" AND \")}`;\n }\n\n sql += ` RETURNING ${this._returning.join(\", \")}`;\n\n const result = await this.client.query(sql, params);\n return {\n data: result.rows as T[],\n count: result.rowCount ?? undefined,\n };\n }\n\n private async executeDelete(): Promise<QueryResult<T>> {\n const params: unknown[] = [];\n let paramIndex = 1;\n\n let sql = `DELETE FROM ${this.tableName}`;\n\n // Build WHERE clause\n const whereClauses: string[] = [];\n\n for (const { column, operator, value } of this._where) {\n whereClauses.push(\n `${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`,\n );\n params.push(value);\n }\n\n for (const { column, values } of this._whereIn) {\n const placeholders = values.map(() => `$${paramIndex++}`).join(\", \");\n whereClauses.push(\n `${this.escapeIdentifier(column)} IN (${placeholders})`,\n );\n params.push(...values);\n }\n\n if (whereClauses.length > 0) {\n sql += ` WHERE ${whereClauses.join(\" AND \")}`;\n }\n\n sql += ` RETURNING ${this._returning.join(\", \")}`;\n\n const result = await this.client.query(sql, params);\n return {\n data: result.rows as T[],\n count: result.rowCount ?? undefined,\n };\n }\n\n private escapeIdentifier(identifier: string): string {\n // Handle special cases\n if (identifier === \"*\") return \"*\";\n\n // Handle schema.table notation\n if (identifier.includes(\".\")) {\n return identifier\n .split(\".\")\n .map((part) => `\"${part.replace(/\"/g, '\"\"')}\"`)\n .join(\".\");\n }\n\n // Escape identifier with double quotes\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n }\n\n private mapOperator(operator: string): string {\n switch (operator.toLowerCase()) {\n case \"=\":\n case \"==\":\n return \"=\";\n case \"!=\":\n case \"<>\":\n return \"<>\";\n case \"<\":\n return \"<\";\n case \"<=\":\n return \"<=\";\n case \">\":\n return \">\";\n case \">=\":\n return \">=\";\n case \"like\":\n return \"LIKE\";\n case \"ilike\":\n return \"ILIKE\";\n case \"is\":\n return \"IS\";\n case \"is not\":\n return \"IS NOT\";\n default:\n return \"=\";\n }\n }\n}\n","/**\n * Database Migrator\n *\n * Enterprise-grade database migration system supporting:\n * - PostgreSQL (primary)\n * - Memory database (for testing)\n * - Transaction-safe migrations\n * - Concurrent execution locking\n * - Checksum validation\n * - Dry-run mode\n */\n\nimport type {\n IMigrator,\n Migration,\n MigrationRecord,\n MigrationResult,\n MigrationStatus,\n MigratorConfig,\n IMigrationDatabase,\n} from \"../interfaces/IMigration\";\n\nconst DEFAULT_CONFIG: Required<Omit<MigratorConfig, \"migrationsDir\">> & {\n migrationsDir?: string;\n} = {\n tableName: \"_migrations\",\n schema: \"public\",\n lockTimeout: 60,\n validateChecksums: true,\n migrationsDir: undefined,\n};\n\n/**\n * Generate a checksum for migration content\n */\nfunction generateChecksum(content: string): string {\n // Simple hash for checksum - in production you might use crypto\n let hash = 0;\n for (let i = 0; i < content.length; i++) {\n const char = content.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32-bit integer\n }\n return Math.abs(hash).toString(16).padStart(8, \"0\");\n}\n\n/**\n * Sort migrations by version\n */\nfunction sortMigrations(migrations: Migration[]): Migration[] {\n return [...migrations].sort((a, b) => a.version.localeCompare(b.version));\n}\n\nexport class Migrator implements IMigrator {\n private db: IMigrationDatabase;\n private config: Required<Omit<MigratorConfig, \"migrationsDir\">> & {\n migrationsDir?: string;\n };\n private migrations: Migration[] = [];\n private initialized = false;\n private locked = false;\n\n constructor(db: IMigrationDatabase, config: MigratorConfig = {}) {\n this.db = db;\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n /**\n * Get the fully qualified migration table name\n */\n private get tableName(): string {\n return `\"${this.config.schema}\".\"${this.config.tableName}\"`;\n }\n\n /**\n * Get the lock table name\n */\n private get lockTableName(): string {\n return `\"${this.config.schema}\".\"${this.config.tableName}_lock\"`;\n }\n\n /**\n * Initialize migration tracking tables\n */\n private async initialize(): Promise<void> {\n if (this.initialized) return;\n\n // Create schema if not exists\n await this.db.raw(`CREATE SCHEMA IF NOT EXISTS \"${this.config.schema}\"`);\n\n // Create migrations tracking table\n await this.db.raw(`\n CREATE TABLE IF NOT EXISTS ${this.tableName} (\n version VARCHAR(255) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n applied_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,\n execution_time INTEGER NOT NULL,\n checksum VARCHAR(64)\n )\n `);\n\n // Create lock table for concurrent safety\n await this.db.raw(`\n CREATE TABLE IF NOT EXISTS ${this.lockTableName} (\n id INTEGER PRIMARY KEY DEFAULT 1,\n locked_at TIMESTAMP WITH TIME ZONE,\n locked_by VARCHAR(255),\n CONSTRAINT single_row CHECK (id = 1)\n )\n `);\n\n // Insert initial lock row if not exists\n await this.db.raw(`\n INSERT INTO ${this.lockTableName} (id, locked_at, locked_by)\n VALUES (1, NULL, NULL)\n ON CONFLICT (id) DO NOTHING\n `);\n\n this.initialized = true;\n }\n\n /**\n * Acquire migration lock\n */\n async lock(): Promise<boolean> {\n await this.initialize();\n\n const lockId = `${process.pid}-${Date.now()}`;\n const lockTimeout = new Date(Date.now() - this.config.lockTimeout * 1000);\n\n // Try to acquire lock (only if not locked or lock expired)\n const result = await this.db.raw<{ locked_at: Date | null }>(\n `\n UPDATE ${this.lockTableName}\n SET locked_at = CURRENT_TIMESTAMP, locked_by = $1\n WHERE id = 1 AND (locked_at IS NULL OR locked_at < $2)\n RETURNING locked_at\n `,\n [lockId, lockTimeout],\n );\n\n if (result.data.length > 0) {\n this.locked = true;\n return true;\n }\n\n return false;\n }\n\n /**\n * Release migration lock\n */\n async unlock(): Promise<void> {\n if (!this.locked) return;\n\n await this.db.raw(\n `\n UPDATE ${this.lockTableName}\n SET locked_at = NULL, locked_by = NULL\n WHERE id = 1\n `,\n );\n\n this.locked = false;\n }\n\n /**\n * Add migrations to the migrator\n */\n addMigrations(migrations: Migration[]): void {\n for (const migration of migrations) {\n // Generate checksum if not provided\n if (!migration.checksum) {\n const content =\n typeof migration.up === \"string\"\n ? migration.up\n : migration.up.toString();\n migration.checksum = generateChecksum(content);\n }\n\n // Avoid duplicates\n if (!this.migrations.find((m) => m.version === migration.version)) {\n this.migrations.push(migration);\n }\n }\n }\n\n /**\n * Load migrations from directory\n * Expects files named: {version}_{name}.ts or {version}_{name}.sql\n */\n async loadMigrations(dir: string): Promise<void> {\n // Dynamic import for Node.js file system\n const { readdir, readFile } = await import(\"fs/promises\");\n const { join } = await import(\"path\");\n\n const files = await readdir(dir);\n const migrationFiles = files.filter((f) =>\n f.match(/^\\d+_.*\\.(ts|js|sql)$/),\n );\n\n for (const file of migrationFiles) {\n const filePath = join(dir, file);\n const [version, ...nameParts] = file\n .replace(/\\.(ts|js|sql)$/, \"\")\n .split(\"_\");\n const name = nameParts.join(\"_\");\n\n if (file.endsWith(\".sql\")) {\n // SQL file - parse UP and DOWN sections\n const content = await readFile(filePath, \"utf-8\");\n const [up, down] = this.parseSqlMigration(content);\n\n this.addMigrations([\n {\n version: version!,\n name,\n up,\n down,\n },\n ]);\n } else {\n // TypeScript/JavaScript file - import the module\n const module = await import(filePath);\n this.addMigrations([\n {\n version: version!,\n name,\n up: module.up,\n down: module.down,\n transactional: module.transactional,\n },\n ]);\n }\n }\n }\n\n /**\n * Parse SQL migration file with -- UP and -- DOWN sections\n */\n private parseSqlMigration(content: string): [string, string] {\n const upMatch = content.match(/--\\s*UP\\s*\\n([\\s\\S]*?)(?=--\\s*DOWN|$)/i);\n const downMatch = content.match(/--\\s*DOWN\\s*\\n([\\s\\S]*?)$/i);\n\n const up = upMatch?.[1]?.trim() ?? content.trim();\n const down = downMatch?.[1]?.trim() ?? \"\";\n\n return [up, down];\n }\n\n /**\n * Get current migration status\n */\n async status(): Promise<MigrationStatus> {\n await this.initialize();\n\n // Get applied migrations\n const result = await this.db.raw<{\n version: string;\n name: string;\n applied_at: Date;\n execution_time: number;\n checksum: string | null;\n }>(\n `SELECT version, name, applied_at, execution_time, checksum\n FROM ${this.tableName}\n ORDER BY version ASC`,\n );\n\n const applied: MigrationRecord[] = result.data.map((row) => ({\n version: row.version,\n name: row.name,\n appliedAt: new Date(row.applied_at),\n executionTime: row.execution_time,\n checksum: row.checksum ?? undefined,\n }));\n\n const appliedVersions = new Set(applied.map((m) => m.version));\n const sortedMigrations = sortMigrations(this.migrations);\n\n const pending = sortedMigrations.filter(\n (m) => !appliedVersions.has(m.version),\n );\n\n return {\n applied,\n pending,\n currentVersion:\n applied.length > 0 ? applied[applied.length - 1]!.version : null,\n latestVersion:\n sortedMigrations.length > 0\n ? sortedMigrations[sortedMigrations.length - 1]!.version\n : null,\n };\n }\n\n /**\n * Run all pending migrations (or up to a specific version)\n */\n async up(\n options: { dryRun?: boolean; to?: string } = {},\n ): Promise<MigrationResult[]> {\n const { dryRun = false, to } = options;\n const results: MigrationResult[] = [];\n\n if (!dryRun) {\n const acquired = await this.lock();\n if (!acquired) {\n throw new Error(\n \"Could not acquire migration lock. Another migration may be in progress.\",\n );\n }\n }\n\n try {\n const status = await this.status();\n let pending = status.pending;\n\n // Filter to specific version if requested\n if (to) {\n const targetIndex = pending.findIndex((m) => m.version === to);\n if (targetIndex === -1) {\n throw new Error(\n `Target version ${to} not found in pending migrations`,\n );\n }\n pending = pending.slice(0, targetIndex + 1);\n }\n\n for (const migration of pending) {\n const result = await this.runMigration(migration, \"up\", dryRun);\n results.push(result);\n\n if (!result.success) {\n break; // Stop on first failure\n }\n }\n } finally {\n if (!dryRun) {\n await this.unlock();\n }\n }\n\n return results;\n }\n\n /**\n * Rollback migrations\n */\n async down(\n options: { dryRun?: boolean; steps?: number } = {},\n ): Promise<MigrationResult[]> {\n const { dryRun = false, steps = 1 } = options;\n const results: MigrationResult[] = [];\n\n if (!dryRun) {\n const acquired = await this.lock();\n if (!acquired) {\n throw new Error(\n \"Could not acquire migration lock. Another migration may be in progress.\",\n );\n }\n }\n\n try {\n const status = await this.status();\n\n // Get the last N applied migrations (in reverse order)\n const toRollback = status.applied.slice(-steps).reverse();\n\n for (const record of toRollback) {\n const migration = this.migrations.find(\n (m) => m.version === record.version,\n );\n if (!migration) {\n throw new Error(\n `Migration ${record.version} was applied but is not registered. Cannot rollback.`,\n );\n }\n\n const result = await this.runMigration(migration, \"down\", dryRun);\n results.push(result);\n\n if (!result.success) {\n break;\n }\n }\n } finally {\n if (!dryRun) {\n await this.unlock();\n }\n }\n\n return results;\n }\n\n /**\n * Rollback all migrations and re-run them\n */\n async reset(options: { dryRun?: boolean } = {}): Promise<MigrationResult[]> {\n const status = await this.status();\n const downResults = await this.down({\n dryRun: options.dryRun,\n steps: status.applied.length,\n });\n\n // Only proceed with up if all downs succeeded\n if (downResults.every((r) => r.success)) {\n const upResults = await this.up({ dryRun: options.dryRun });\n return [...downResults, ...upResults];\n }\n\n return downResults;\n }\n\n /**\n * Migrate to a specific version\n */\n async goto(\n version: string,\n options: { dryRun?: boolean } = {},\n ): Promise<MigrationResult[]> {\n const status = await this.status();\n const currentVersion = status.currentVersion;\n const results: MigrationResult[] = [];\n\n // If already at target, nothing to do\n if (currentVersion === version) {\n return results;\n }\n\n // Determine direction\n const isUp = !currentVersion || version > currentVersion;\n\n if (isUp) {\n return this.up({ ...options, to: version });\n } else {\n // Find how many steps down we need to go\n const currentIndex = status.applied.findIndex(\n (m) => m.version === currentVersion,\n );\n const targetIndex = status.applied.findIndex(\n (m) => m.version === version,\n );\n\n if (targetIndex === -1) {\n throw new Error(\n `Target version ${version} not found in applied migrations`,\n );\n }\n\n const steps = currentIndex - targetIndex;\n return this.down({ ...options, steps });\n }\n }\n\n /**\n * Run a single migration\n */\n private async runMigration(\n migration: Migration,\n direction: \"up\" | \"down\",\n dryRun: boolean,\n ): Promise<MigrationResult> {\n const startTime = Date.now();\n const action = direction === \"up\" ? migration.up : migration.down;\n\n try {\n if (dryRun) {\n // Just simulate - don't actually run\n return {\n migration,\n success: true,\n executionTime: 0,\n dryRun: true,\n };\n }\n\n const transactional = migration.transactional !== false;\n const runAction = async (db: IMigrationDatabase) => {\n if (typeof action === \"string\") {\n const result = await db.raw(action);\n if (result.error) {\n throw result.error;\n }\n } else {\n await action(db);\n }\n };\n\n if (transactional) {\n await this.db.transaction(async (tx) => {\n await runAction(tx);\n });\n } else {\n await runAction(this.db);\n }\n\n const executionTime = Date.now() - startTime;\n\n // Update tracking table\n if (direction === \"up\") {\n await this.db.raw(\n `INSERT INTO ${this.tableName} (version, name, execution_time, checksum)\n VALUES ($1, $2, $3, $4)`,\n [\n migration.version,\n migration.name,\n executionTime,\n migration.checksum,\n ],\n );\n } else {\n await this.db.raw(`DELETE FROM ${this.tableName} WHERE version = $1`, [\n migration.version,\n ]);\n }\n\n return {\n migration,\n success: true,\n executionTime,\n dryRun: false,\n };\n } catch (error) {\n return {\n migration,\n success: false,\n executionTime: Date.now() - startTime,\n error: error instanceof Error ? error : new Error(String(error)),\n dryRun: false,\n };\n }\n }\n\n /**\n * Create a new migration file\n */\n async create(name: string): Promise<string> {\n const { writeFile, mkdir } = await import(\"fs/promises\");\n const { join } = await import(\"path\");\n\n if (!this.config.migrationsDir) {\n throw new Error(\"migrationsDir must be configured to create migrations\");\n }\n\n // Ensure directory exists\n await mkdir(this.config.migrationsDir, { recursive: true });\n\n // Generate version timestamp\n const now = new Date();\n const version = [\n now.getFullYear(),\n String(now.getMonth() + 1).padStart(2, \"0\"),\n String(now.getDate()).padStart(2, \"0\"),\n String(now.getHours()).padStart(2, \"0\"),\n String(now.getMinutes()).padStart(2, \"0\"),\n String(now.getSeconds()).padStart(2, \"0\"),\n ].join(\"\");\n\n const safeName = name.replace(/[^a-zA-Z0-9_]/g, \"_\").toLowerCase();\n const fileName = `${version}_${safeName}.sql`;\n const filePath = join(this.config.migrationsDir, fileName);\n\n const template = `-- Migration: ${name}\n-- Version: ${version}\n-- Created: ${now.toISOString()}\n\n-- UP\n-- Add your forward migration SQL here\n\n\n-- DOWN\n-- Add your rollback migration SQL here\n\n`;\n\n await writeFile(filePath, template, \"utf-8\");\n\n return filePath;\n }\n\n /**\n * Validate migration integrity\n */\n async validate(): Promise<{ valid: boolean; errors: string[] }> {\n const errors: string[] = [];\n const status = await this.status();\n\n if (!this.config.validateChecksums) {\n return { valid: true, errors };\n }\n\n for (const applied of status.applied) {\n const migration = this.migrations.find(\n (m) => m.version === applied.version,\n );\n\n if (!migration) {\n errors.push(\n `Migration ${applied.version} (${applied.name}) was applied but is not registered`,\n );\n continue;\n }\n\n if (applied.checksum && migration.checksum !== applied.checksum) {\n errors.push(\n `Migration ${applied.version} (${applied.name}) has been modified since it was applied`,\n );\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n }\n}\n","#!/usr/bin/env node\n/**\n * Database Migration CLI\n *\n * Command-line interface for running database migrations.\n *\n * Usage:\n * npx platform-migrate status # Show migration status\n * npx platform-migrate up # Run all pending migrations\n * npx platform-migrate up --to V # Run migrations up to version V\n * npx platform-migrate up --dry-run # Preview without applying\n * npx platform-migrate down # Rollback last migration\n * npx platform-migrate down --steps N # Rollback last N migrations\n * npx platform-migrate reset # Rollback all and re-run\n * npx platform-migrate create NAME # Create new migration file\n * npx platform-migrate validate # Validate migration integrity\n *\n * Environment Variables:\n * DATABASE_URL - PostgreSQL connection string\n * MIGRATIONS_DIR - Directory containing migration files (default: ./migrations)\n * MIGRATIONS_TABLE - Table name for tracking (default: _migrations)\n */\n\nimport { Migrator } from \"./Migrator\";\nimport type { MigrationResult } from \"../interfaces/IMigration\";\n\ninterface CliOptions {\n command: string;\n dryRun: boolean;\n steps: number;\n to?: string;\n name?: string;\n migrationsDir: string;\n help: boolean;\n}\n\nconst HELP_TEXT = `\nDatabase Migration CLI\n\nUSAGE:\n platform-migrate <command> [options]\n\nCOMMANDS:\n status Show current migration status\n up Run all pending migrations\n down Rollback the last migration\n reset Rollback all and re-run migrations\n goto <ver> Migrate to a specific version\n create <name> Create a new migration file\n validate Validate migration integrity\n\nOPTIONS:\n --dry-run Preview changes without applying\n --steps <n> Number of migrations to rollback (for down command)\n --to <ver> Target version (for up command)\n --dir <path> Migrations directory (default: ./migrations)\n --help, -h Show this help message\n\nENVIRONMENT:\n DATABASE_URL PostgreSQL connection string (required)\n MIGRATIONS_DIR Default migrations directory\n MIGRATIONS_TABLE Migration tracking table name\n\nEXAMPLES:\n platform-migrate status\n platform-migrate up\n platform-migrate up --dry-run\n platform-migrate down --steps 3\n platform-migrate create add_users_table\n platform-migrate goto 20240101000000\n`;\n\nfunction parseArgs(args: string[]): CliOptions {\n const options: CliOptions = {\n command: \"\",\n dryRun: false,\n steps: 1,\n migrationsDir: process.env.MIGRATIONS_DIR ?? \"./migrations\",\n help: false,\n };\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]!;\n\n if (arg === \"--dry-run\") {\n options.dryRun = true;\n } else if (arg === \"--steps\" && args[i + 1]) {\n options.steps = parseInt(args[++i]!, 10);\n } else if (arg === \"--to\" && args[i + 1]) {\n options.to = args[++i];\n } else if ((arg === \"--dir\" || arg === \"-d\") && args[i + 1]) {\n options.migrationsDir = args[++i]!;\n } else if (arg === \"--help\" || arg === \"-h\") {\n options.help = true;\n } else if (!arg.startsWith(\"-\") && !options.command) {\n options.command = arg;\n } else if (!arg.startsWith(\"-\") && options.command && !options.name) {\n options.name = arg;\n }\n }\n\n return options;\n}\n\nfunction formatResults(results: MigrationResult[]): void {\n if (results.length === 0) {\n console.log(\"No migrations to run.\");\n return;\n }\n\n for (const result of results) {\n const icon = result.success ? \"✓\" : \"✗\";\n const status = result.dryRun ? \"[DRY RUN]\" : \"\";\n const time = result.success ? `(${result.executionTime}ms)` : \"\";\n\n if (result.success) {\n console.log(\n ` ${icon} ${result.migration.version} - ${result.migration.name} ${time} ${status}`,\n );\n } else {\n console.error(\n ` ${icon} ${result.migration.version} - ${result.migration.name}`,\n );\n console.error(` Error: ${result.error?.message}`);\n }\n }\n\n const successful = results.filter((r) => r.success).length;\n const failed = results.filter((r) => !r.success).length;\n\n console.log(`\\n${successful} successful, ${failed} failed`);\n}\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n const options = parseArgs(args);\n\n if (options.help || !options.command) {\n console.log(HELP_TEXT);\n process.exit(options.help ? 0 : 1);\n }\n\n // Check for DATABASE_URL\n if (!process.env.DATABASE_URL) {\n console.error(\"Error: DATABASE_URL environment variable is required\");\n process.exit(1);\n }\n\n try {\n // Dynamic import PostgresDatabase to keep dependencies optional\n const { PostgresDatabase } =\n await import(\"../adapters/postgres/PostgresDatabase\");\n const db = await PostgresDatabase.fromEnv();\n\n const migrator = new Migrator(db, {\n tableName: process.env.MIGRATIONS_TABLE ?? \"_migrations\",\n migrationsDir: options.migrationsDir,\n });\n\n // Load migrations from directory\n try {\n await migrator.loadMigrations(options.migrationsDir);\n } catch (e) {\n // Directory may not exist for some commands\n if (options.command !== \"create\") {\n console.warn(\n `Warning: Could not load migrations from ${options.migrationsDir}`,\n );\n }\n }\n\n switch (options.command) {\n case \"status\": {\n const status = await migrator.status();\n console.log(\"\\n=== Migration Status ===\\n\");\n console.log(`Current Version: ${status.currentVersion ?? \"None\"}`);\n console.log(`Latest Version: ${status.latestVersion ?? \"None\"}`);\n console.log(`\\nApplied (${status.applied.length}):`);\n for (const m of status.applied) {\n console.log(\n ` ✓ ${m.version} - ${m.name} (${m.appliedAt.toISOString()})`,\n );\n }\n console.log(`\\nPending (${status.pending.length}):`);\n for (const m of status.pending) {\n console.log(` ○ ${m.version} - ${m.name}`);\n }\n break;\n }\n\n case \"up\": {\n console.log(\n options.dryRun\n ? \"\\n=== Dry Run: Migrate Up ===\\n\"\n : \"\\n=== Migrating Up ===\\n\",\n );\n const results = await migrator.up({\n dryRun: options.dryRun,\n to: options.to,\n });\n formatResults(results);\n if (results.some((r) => !r.success)) {\n process.exit(1);\n }\n break;\n }\n\n case \"down\": {\n console.log(\n options.dryRun\n ? \"\\n=== Dry Run: Rollback ===\\n\"\n : \"\\n=== Rolling Back ===\\n\",\n );\n const results = await migrator.down({\n dryRun: options.dryRun,\n steps: options.steps,\n });\n formatResults(results);\n if (results.some((r) => !r.success)) {\n process.exit(1);\n }\n break;\n }\n\n case \"reset\": {\n console.log(\n options.dryRun\n ? \"\\n=== Dry Run: Reset ===\\n\"\n : \"\\n=== Resetting Database ===\\n\",\n );\n const results = await migrator.reset({ dryRun: options.dryRun });\n formatResults(results);\n if (results.some((r) => !r.success)) {\n process.exit(1);\n }\n break;\n }\n\n case \"goto\": {\n if (!options.name) {\n console.error(\n \"Error: Version required. Usage: platform-migrate goto <version>\",\n );\n process.exit(1);\n }\n console.log(`\\n=== Migrating to Version ${options.name} ===\\n`);\n const results = await migrator.goto(options.name, {\n dryRun: options.dryRun,\n });\n formatResults(results);\n if (results.some((r) => !r.success)) {\n process.exit(1);\n }\n break;\n }\n\n case \"create\": {\n if (!options.name) {\n console.error(\n \"Error: Migration name required. Usage: platform-migrate create <name>\",\n );\n process.exit(1);\n }\n const filePath = await migrator.create(options.name);\n console.log(`\\nCreated migration: ${filePath}\\n`);\n break;\n }\n\n case \"validate\": {\n console.log(\"\\n=== Validating Migrations ===\\n\");\n const { valid, errors } = await migrator.validate();\n if (valid) {\n console.log(\"✓ All migrations are valid\");\n } else {\n console.error(\"✗ Validation failed:\");\n for (const error of errors) {\n console.error(` - ${error}`);\n }\n process.exit(1);\n }\n break;\n }\n\n default:\n console.error(`Unknown command: ${options.command}`);\n console.log(HELP_TEXT);\n process.exit(1);\n }\n\n await db.close();\n } catch (error) {\n console.error(\"Error:\", error instanceof Error ? error.message : error);\n process.exit(1);\n }\n}\n\n// Run if executed directly\nmain().catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n});\n"],"mappings":"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","names":["module","PostgresDatabase"]}
@@ -257,7 +257,9 @@ var Migrator = class {
257
257
  if (!dryRun) {
258
258
  const acquired = await this.lock();
259
259
  if (!acquired) {
260
- throw new Error("Could not acquire migration lock. Another migration may be in progress.");
260
+ throw new Error(
261
+ "Could not acquire migration lock. Another migration may be in progress."
262
+ );
261
263
  }
262
264
  }
263
265
  try {
@@ -266,7 +268,9 @@ var Migrator = class {
266
268
  if (to) {
267
269
  const targetIndex = pending.findIndex((m) => m.version === to);
268
270
  if (targetIndex === -1) {
269
- throw new Error(`Target version ${to} not found in pending migrations`);
271
+ throw new Error(
272
+ `Target version ${to} not found in pending migrations`
273
+ );
270
274
  }
271
275
  pending = pending.slice(0, targetIndex + 1);
272
276
  }
@@ -293,14 +297,18 @@ var Migrator = class {
293
297
  if (!dryRun) {
294
298
  const acquired = await this.lock();
295
299
  if (!acquired) {
296
- throw new Error("Could not acquire migration lock. Another migration may be in progress.");
300
+ throw new Error(
301
+ "Could not acquire migration lock. Another migration may be in progress."
302
+ );
297
303
  }
298
304
  }
299
305
  try {
300
306
  const status = await this.status();
301
307
  const toRollback = status.applied.slice(-steps).reverse();
302
308
  for (const record of toRollback) {
303
- const migration = this.migrations.find((m) => m.version === record.version);
309
+ const migration = this.migrations.find(
310
+ (m) => m.version === record.version
311
+ );
304
312
  if (!migration) {
305
313
  throw new Error(
306
314
  `Migration ${record.version} was applied but is not registered. Cannot rollback.`
@@ -348,10 +356,16 @@ var Migrator = class {
348
356
  if (isUp) {
349
357
  return this.up({ ...options, to: version });
350
358
  } else {
351
- const currentIndex = status.applied.findIndex((m) => m.version === currentVersion);
352
- const targetIndex = status.applied.findIndex((m) => m.version === version);
359
+ const currentIndex = status.applied.findIndex(
360
+ (m) => m.version === currentVersion
361
+ );
362
+ const targetIndex = status.applied.findIndex(
363
+ (m) => m.version === version
364
+ );
353
365
  if (targetIndex === -1) {
354
- throw new Error(`Target version ${version} not found in applied migrations`);
366
+ throw new Error(
367
+ `Target version ${version} not found in applied migrations`
368
+ );
355
369
  }
356
370
  const steps = currentIndex - targetIndex;
357
371
  return this.down({ ...options, steps });
@@ -395,13 +409,17 @@ var Migrator = class {
395
409
  await this.db.raw(
396
410
  `INSERT INTO ${this.tableName} (version, name, execution_time, checksum)
397
411
  VALUES ($1, $2, $3, $4)`,
398
- [migration.version, migration.name, executionTime, migration.checksum]
412
+ [
413
+ migration.version,
414
+ migration.name,
415
+ executionTime,
416
+ migration.checksum
417
+ ]
399
418
  );
400
419
  } else {
401
- await this.db.raw(
402
- `DELETE FROM ${this.tableName} WHERE version = $1`,
403
- [migration.version]
404
- );
420
+ await this.db.raw(`DELETE FROM ${this.tableName} WHERE version = $1`, [
421
+ migration.version
422
+ ]);
405
423
  }
406
424
  return {
407
425
  migration,
@@ -466,7 +484,9 @@ var Migrator = class {
466
484
  return { valid: true, errors };
467
485
  }
468
486
  for (const applied of status.applied) {
469
- const migration = this.migrations.find((m) => m.version === applied.version);
487
+ const migration = this.migrations.find(
488
+ (m) => m.version === applied.version
489
+ );
470
490
  if (!migration) {
471
491
  errors.push(
472
492
  `Migration ${applied.version} (${applied.name}) was applied but is not registered`
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/migrations/index.ts","../../src/migrations/Migrator.ts","../../src/migrations/helpers.ts","../../src/migrations/enterprise.ts"],"sourcesContent":["/**\n * Database Migrations\n *\n * Enterprise-grade migration system for managing database schema changes.\n *\n * @example\n * ```typescript\n * import { Migrator } from '@digilogiclabs/platform-core';\n * import { PostgresDatabase } from '@digilogiclabs/platform-core';\n *\n * // Create database connection\n * const db = await PostgresDatabase.fromEnv();\n *\n * // Create migrator\n * const migrator = new Migrator(db, {\n * tableName: '_migrations',\n * migrationsDir: './migrations'\n * });\n *\n * // Add migrations programmatically\n * migrator.addMigrations([\n * {\n * version: '20240101000000',\n * name: 'create_users_table',\n * up: `CREATE TABLE users (id UUID PRIMARY KEY, email VARCHAR(255) UNIQUE)`,\n * down: `DROP TABLE users`\n * }\n * ]);\n *\n * // Or load from directory\n * await migrator.loadMigrations('./migrations');\n *\n * // Check status\n * const status = await migrator.status();\n * console.log('Applied:', status.applied.length);\n * console.log('Pending:', status.pending.length);\n *\n * // Run pending migrations\n * const results = await migrator.up();\n * for (const result of results) {\n * if (result.success) {\n * console.log(`✓ ${result.migration.name} (${result.executionTime}ms)`);\n * } else {\n * console.error(`✗ ${result.migration.name}: ${result.error?.message}`);\n * }\n * }\n *\n * // Rollback last migration\n * await migrator.down();\n *\n * // Rollback last 3 migrations\n * await migrator.down({ steps: 3 });\n *\n * // Dry run (preview without applying)\n * await migrator.up({ dryRun: true });\n * ```\n */\n\nexport { Migrator } from \"./Migrator\";\nexport type {\n Migration,\n MigrationRecord,\n MigrationResult,\n MigrationStatus,\n MigratorConfig,\n IMigrator,\n IMigrationDatabase,\n} from \"../interfaces/IMigration\";\n\n// Re-export common migration patterns\nexport { createMigration, defineMigration, sqlMigration } from \"./helpers\";\n\n// Enterprise migrations for SSO and multi-tenancy\nexport {\n enterpriseMigrations,\n getEnterpriseMigrations,\n createSsoOidcConfigsTable,\n createDomainVerificationsTable,\n createVerifiedDomainsTable,\n createTenantsTable,\n createTenantMembersTable,\n createTenantInvitationsTable,\n createTenantUsageTable,\n createSsoSessionsTable,\n} from \"./enterprise\";\n","/**\r\n * Database Migrator\r\n *\r\n * Enterprise-grade database migration system supporting:\r\n * - PostgreSQL (primary)\r\n * - Memory database (for testing)\r\n * - Transaction-safe migrations\r\n * - Concurrent execution locking\r\n * - Checksum validation\r\n * - Dry-run mode\r\n */\r\n\r\nimport type {\r\n IMigrator,\r\n Migration,\r\n MigrationRecord,\r\n MigrationResult,\r\n MigrationStatus,\r\n MigratorConfig,\r\n IMigrationDatabase,\r\n} from '../interfaces/IMigration';\r\n\r\nconst DEFAULT_CONFIG: Required<Omit<MigratorConfig, 'migrationsDir'>> & { migrationsDir?: string } = {\r\n tableName: '_migrations',\r\n schema: 'public',\r\n lockTimeout: 60,\r\n validateChecksums: true,\r\n migrationsDir: undefined,\r\n};\r\n\r\n/**\r\n * Generate a checksum for migration content\r\n */\r\nfunction generateChecksum(content: string): string {\r\n // Simple hash for checksum - in production you might use crypto\r\n let hash = 0;\r\n for (let i = 0; i < content.length; i++) {\r\n const char = content.charCodeAt(i);\r\n hash = (hash << 5) - hash + char;\r\n hash = hash & hash; // Convert to 32-bit integer\r\n }\r\n return Math.abs(hash).toString(16).padStart(8, '0');\r\n}\r\n\r\n/**\r\n * Sort migrations by version\r\n */\r\nfunction sortMigrations(migrations: Migration[]): Migration[] {\r\n return [...migrations].sort((a, b) => a.version.localeCompare(b.version));\r\n}\r\n\r\nexport class Migrator implements IMigrator {\r\n private db: IMigrationDatabase;\r\n private config: Required<Omit<MigratorConfig, 'migrationsDir'>> & { migrationsDir?: string };\r\n private migrations: Migration[] = [];\r\n private initialized = false;\r\n private locked = false;\r\n\r\n constructor(db: IMigrationDatabase, config: MigratorConfig = {}) {\r\n this.db = db;\r\n this.config = { ...DEFAULT_CONFIG, ...config };\r\n }\r\n\r\n /**\r\n * Get the fully qualified migration table name\r\n */\r\n private get tableName(): string {\r\n return `\"${this.config.schema}\".\"${this.config.tableName}\"`;\r\n }\r\n\r\n /**\r\n * Get the lock table name\r\n */\r\n private get lockTableName(): string {\r\n return `\"${this.config.schema}\".\"${this.config.tableName}_lock\"`;\r\n }\r\n\r\n /**\r\n * Initialize migration tracking tables\r\n */\r\n private async initialize(): Promise<void> {\r\n if (this.initialized) return;\r\n\r\n // Create schema if not exists\r\n await this.db.raw(`CREATE SCHEMA IF NOT EXISTS \"${this.config.schema}\"`);\r\n\r\n // Create migrations tracking table\r\n await this.db.raw(`\r\n CREATE TABLE IF NOT EXISTS ${this.tableName} (\r\n version VARCHAR(255) PRIMARY KEY,\r\n name VARCHAR(255) NOT NULL,\r\n applied_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,\r\n execution_time INTEGER NOT NULL,\r\n checksum VARCHAR(64)\r\n )\r\n `);\r\n\r\n // Create lock table for concurrent safety\r\n await this.db.raw(`\r\n CREATE TABLE IF NOT EXISTS ${this.lockTableName} (\r\n id INTEGER PRIMARY KEY DEFAULT 1,\r\n locked_at TIMESTAMP WITH TIME ZONE,\r\n locked_by VARCHAR(255),\r\n CONSTRAINT single_row CHECK (id = 1)\r\n )\r\n `);\r\n\r\n // Insert initial lock row if not exists\r\n await this.db.raw(`\r\n INSERT INTO ${this.lockTableName} (id, locked_at, locked_by)\r\n VALUES (1, NULL, NULL)\r\n ON CONFLICT (id) DO NOTHING\r\n `);\r\n\r\n this.initialized = true;\r\n }\r\n\r\n /**\r\n * Acquire migration lock\r\n */\r\n async lock(): Promise<boolean> {\r\n await this.initialize();\r\n\r\n const lockId = `${process.pid}-${Date.now()}`;\r\n const lockTimeout = new Date(Date.now() - this.config.lockTimeout * 1000);\r\n\r\n // Try to acquire lock (only if not locked or lock expired)\r\n const result = await this.db.raw<{ locked_at: Date | null }>(\r\n `\r\n UPDATE ${this.lockTableName}\r\n SET locked_at = CURRENT_TIMESTAMP, locked_by = $1\r\n WHERE id = 1 AND (locked_at IS NULL OR locked_at < $2)\r\n RETURNING locked_at\r\n `,\r\n [lockId, lockTimeout]\r\n );\r\n\r\n if (result.data.length > 0) {\r\n this.locked = true;\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Release migration lock\r\n */\r\n async unlock(): Promise<void> {\r\n if (!this.locked) return;\r\n\r\n await this.db.raw(\r\n `\r\n UPDATE ${this.lockTableName}\r\n SET locked_at = NULL, locked_by = NULL\r\n WHERE id = 1\r\n `\r\n );\r\n\r\n this.locked = false;\r\n }\r\n\r\n /**\r\n * Add migrations to the migrator\r\n */\r\n addMigrations(migrations: Migration[]): void {\r\n for (const migration of migrations) {\r\n // Generate checksum if not provided\r\n if (!migration.checksum) {\r\n const content =\r\n typeof migration.up === 'string' ? migration.up : migration.up.toString();\r\n migration.checksum = generateChecksum(content);\r\n }\r\n\r\n // Avoid duplicates\r\n if (!this.migrations.find((m) => m.version === migration.version)) {\r\n this.migrations.push(migration);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Load migrations from directory\r\n * Expects files named: {version}_{name}.ts or {version}_{name}.sql\r\n */\r\n async loadMigrations(dir: string): Promise<void> {\r\n // Dynamic import for Node.js file system\r\n const { readdir, readFile } = await import('fs/promises');\r\n const { join } = await import('path');\r\n\r\n const files = await readdir(dir);\r\n const migrationFiles = files.filter(\r\n (f) => f.match(/^\\d+_.*\\.(ts|js|sql)$/)\r\n );\r\n\r\n for (const file of migrationFiles) {\r\n const filePath = join(dir, file);\r\n const [version, ...nameParts] = file.replace(/\\.(ts|js|sql)$/, '').split('_');\r\n const name = nameParts.join('_');\r\n\r\n if (file.endsWith('.sql')) {\r\n // SQL file - parse UP and DOWN sections\r\n const content = await readFile(filePath, 'utf-8');\r\n const [up, down] = this.parseSqlMigration(content);\r\n\r\n this.addMigrations([\r\n {\r\n version: version!,\r\n name,\r\n up,\r\n down,\r\n },\r\n ]);\r\n } else {\r\n // TypeScript/JavaScript file - import the module\r\n const module = await import(filePath);\r\n this.addMigrations([\r\n {\r\n version: version!,\r\n name,\r\n up: module.up,\r\n down: module.down,\r\n transactional: module.transactional,\r\n },\r\n ]);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Parse SQL migration file with -- UP and -- DOWN sections\r\n */\r\n private parseSqlMigration(content: string): [string, string] {\r\n const upMatch = content.match(/--\\s*UP\\s*\\n([\\s\\S]*?)(?=--\\s*DOWN|$)/i);\r\n const downMatch = content.match(/--\\s*DOWN\\s*\\n([\\s\\S]*?)$/i);\r\n\r\n const up = upMatch?.[1]?.trim() ?? content.trim();\r\n const down = downMatch?.[1]?.trim() ?? '';\r\n\r\n return [up, down];\r\n }\r\n\r\n /**\r\n * Get current migration status\r\n */\r\n async status(): Promise<MigrationStatus> {\r\n await this.initialize();\r\n\r\n // Get applied migrations\r\n const result = await this.db.raw<{\r\n version: string;\r\n name: string;\r\n applied_at: Date;\r\n execution_time: number;\r\n checksum: string | null;\r\n }>(\r\n `SELECT version, name, applied_at, execution_time, checksum\r\n FROM ${this.tableName}\r\n ORDER BY version ASC`\r\n );\r\n\r\n const applied: MigrationRecord[] = result.data.map((row) => ({\r\n version: row.version,\r\n name: row.name,\r\n appliedAt: new Date(row.applied_at),\r\n executionTime: row.execution_time,\r\n checksum: row.checksum ?? undefined,\r\n }));\r\n\r\n const appliedVersions = new Set(applied.map((m) => m.version));\r\n const sortedMigrations = sortMigrations(this.migrations);\r\n\r\n const pending = sortedMigrations.filter(\r\n (m) => !appliedVersions.has(m.version)\r\n );\r\n\r\n return {\r\n applied,\r\n pending,\r\n currentVersion: applied.length > 0 ? applied[applied.length - 1]!.version : null,\r\n latestVersion:\r\n sortedMigrations.length > 0\r\n ? sortedMigrations[sortedMigrations.length - 1]!.version\r\n : null,\r\n };\r\n }\r\n\r\n /**\r\n * Run all pending migrations (or up to a specific version)\r\n */\r\n async up(options: { dryRun?: boolean; to?: string } = {}): Promise<MigrationResult[]> {\r\n const { dryRun = false, to } = options;\r\n const results: MigrationResult[] = [];\r\n\r\n if (!dryRun) {\r\n const acquired = await this.lock();\r\n if (!acquired) {\r\n throw new Error('Could not acquire migration lock. Another migration may be in progress.');\r\n }\r\n }\r\n\r\n try {\r\n const status = await this.status();\r\n let pending = status.pending;\r\n\r\n // Filter to specific version if requested\r\n if (to) {\r\n const targetIndex = pending.findIndex((m) => m.version === to);\r\n if (targetIndex === -1) {\r\n throw new Error(`Target version ${to} not found in pending migrations`);\r\n }\r\n pending = pending.slice(0, targetIndex + 1);\r\n }\r\n\r\n for (const migration of pending) {\r\n const result = await this.runMigration(migration, 'up', dryRun);\r\n results.push(result);\r\n\r\n if (!result.success) {\r\n break; // Stop on first failure\r\n }\r\n }\r\n } finally {\r\n if (!dryRun) {\r\n await this.unlock();\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Rollback migrations\r\n */\r\n async down(options: { dryRun?: boolean; steps?: number } = {}): Promise<MigrationResult[]> {\r\n const { dryRun = false, steps = 1 } = options;\r\n const results: MigrationResult[] = [];\r\n\r\n if (!dryRun) {\r\n const acquired = await this.lock();\r\n if (!acquired) {\r\n throw new Error('Could not acquire migration lock. Another migration may be in progress.');\r\n }\r\n }\r\n\r\n try {\r\n const status = await this.status();\r\n\r\n // Get the last N applied migrations (in reverse order)\r\n const toRollback = status.applied.slice(-steps).reverse();\r\n\r\n for (const record of toRollback) {\r\n const migration = this.migrations.find((m) => m.version === record.version);\r\n if (!migration) {\r\n throw new Error(\r\n `Migration ${record.version} was applied but is not registered. Cannot rollback.`\r\n );\r\n }\r\n\r\n const result = await this.runMigration(migration, 'down', dryRun);\r\n results.push(result);\r\n\r\n if (!result.success) {\r\n break;\r\n }\r\n }\r\n } finally {\r\n if (!dryRun) {\r\n await this.unlock();\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Rollback all migrations and re-run them\r\n */\r\n async reset(options: { dryRun?: boolean } = {}): Promise<MigrationResult[]> {\r\n const status = await this.status();\r\n const downResults = await this.down({\r\n dryRun: options.dryRun,\r\n steps: status.applied.length,\r\n });\r\n\r\n // Only proceed with up if all downs succeeded\r\n if (downResults.every((r) => r.success)) {\r\n const upResults = await this.up({ dryRun: options.dryRun });\r\n return [...downResults, ...upResults];\r\n }\r\n\r\n return downResults;\r\n }\r\n\r\n /**\r\n * Migrate to a specific version\r\n */\r\n async goto(version: string, options: { dryRun?: boolean } = {}): Promise<MigrationResult[]> {\r\n const status = await this.status();\r\n const currentVersion = status.currentVersion;\r\n const results: MigrationResult[] = [];\r\n\r\n // If already at target, nothing to do\r\n if (currentVersion === version) {\r\n return results;\r\n }\r\n\r\n // Determine direction\r\n const isUp = !currentVersion || version > currentVersion;\r\n\r\n if (isUp) {\r\n return this.up({ ...options, to: version });\r\n } else {\r\n // Find how many steps down we need to go\r\n const currentIndex = status.applied.findIndex((m) => m.version === currentVersion);\r\n const targetIndex = status.applied.findIndex((m) => m.version === version);\r\n\r\n if (targetIndex === -1) {\r\n throw new Error(`Target version ${version} not found in applied migrations`);\r\n }\r\n\r\n const steps = currentIndex - targetIndex;\r\n return this.down({ ...options, steps });\r\n }\r\n }\r\n\r\n /**\r\n * Run a single migration\r\n */\r\n private async runMigration(\r\n migration: Migration,\r\n direction: 'up' | 'down',\r\n dryRun: boolean\r\n ): Promise<MigrationResult> {\r\n const startTime = Date.now();\r\n const action = direction === 'up' ? migration.up : migration.down;\r\n\r\n try {\r\n if (dryRun) {\r\n // Just simulate - don't actually run\r\n return {\r\n migration,\r\n success: true,\r\n executionTime: 0,\r\n dryRun: true,\r\n };\r\n }\r\n\r\n const transactional = migration.transactional !== false;\r\n const runAction = async (db: IMigrationDatabase) => {\r\n if (typeof action === 'string') {\r\n const result = await db.raw(action);\r\n if (result.error) {\r\n throw result.error;\r\n }\r\n } else {\r\n await action(db);\r\n }\r\n };\r\n\r\n if (transactional) {\r\n await this.db.transaction(async (tx) => {\r\n await runAction(tx);\r\n });\r\n } else {\r\n await runAction(this.db);\r\n }\r\n\r\n const executionTime = Date.now() - startTime;\r\n\r\n // Update tracking table\r\n if (direction === 'up') {\r\n await this.db.raw(\r\n `INSERT INTO ${this.tableName} (version, name, execution_time, checksum)\r\n VALUES ($1, $2, $3, $4)`,\r\n [migration.version, migration.name, executionTime, migration.checksum]\r\n );\r\n } else {\r\n await this.db.raw(\r\n `DELETE FROM ${this.tableName} WHERE version = $1`,\r\n [migration.version]\r\n );\r\n }\r\n\r\n return {\r\n migration,\r\n success: true,\r\n executionTime,\r\n dryRun: false,\r\n };\r\n } catch (error) {\r\n return {\r\n migration,\r\n success: false,\r\n executionTime: Date.now() - startTime,\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n dryRun: false,\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Create a new migration file\r\n */\r\n async create(name: string): Promise<string> {\r\n const { writeFile, mkdir } = await import('fs/promises');\r\n const { join } = await import('path');\r\n\r\n if (!this.config.migrationsDir) {\r\n throw new Error('migrationsDir must be configured to create migrations');\r\n }\r\n\r\n // Ensure directory exists\r\n await mkdir(this.config.migrationsDir, { recursive: true });\r\n\r\n // Generate version timestamp\r\n const now = new Date();\r\n const version = [\r\n now.getFullYear(),\r\n String(now.getMonth() + 1).padStart(2, '0'),\r\n String(now.getDate()).padStart(2, '0'),\r\n String(now.getHours()).padStart(2, '0'),\r\n String(now.getMinutes()).padStart(2, '0'),\r\n String(now.getSeconds()).padStart(2, '0'),\r\n ].join('');\r\n\r\n const safeName = name.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase();\r\n const fileName = `${version}_${safeName}.sql`;\r\n const filePath = join(this.config.migrationsDir, fileName);\r\n\r\n const template = `-- Migration: ${name}\r\n-- Version: ${version}\r\n-- Created: ${now.toISOString()}\r\n\r\n-- UP\r\n-- Add your forward migration SQL here\r\n\r\n\r\n-- DOWN\r\n-- Add your rollback migration SQL here\r\n\r\n`;\r\n\r\n await writeFile(filePath, template, 'utf-8');\r\n\r\n return filePath;\r\n }\r\n\r\n /**\r\n * Validate migration integrity\r\n */\r\n async validate(): Promise<{ valid: boolean; errors: string[] }> {\r\n const errors: string[] = [];\r\n const status = await this.status();\r\n\r\n if (!this.config.validateChecksums) {\r\n return { valid: true, errors };\r\n }\r\n\r\n for (const applied of status.applied) {\r\n const migration = this.migrations.find((m) => m.version === applied.version);\r\n\r\n if (!migration) {\r\n errors.push(\r\n `Migration ${applied.version} (${applied.name}) was applied but is not registered`\r\n );\r\n continue;\r\n }\r\n\r\n if (applied.checksum && migration.checksum !== applied.checksum) {\r\n errors.push(\r\n `Migration ${applied.version} (${applied.name}) has been modified since it was applied`\r\n );\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n }\r\n}\r\n","/**\r\n * Migration Helper Functions\r\n *\r\n * Utilities for creating migrations in a type-safe and convenient way.\r\n */\r\n\r\nimport type { Migration, IMigrationDatabase } from '../interfaces/IMigration';\r\n\r\n/**\r\n * Create a SQL-based migration\r\n *\r\n * @example\r\n * ```typescript\r\n * export default sqlMigration({\r\n * version: '20240101000000',\r\n * name: 'create_users',\r\n * up: `\r\n * CREATE TABLE users (\r\n * id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\r\n * email VARCHAR(255) UNIQUE NOT NULL,\r\n * created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\r\n * )\r\n * `,\r\n * down: `DROP TABLE users`\r\n * });\r\n * ```\r\n */\r\nexport function sqlMigration(migration: {\r\n version: string;\r\n name: string;\r\n up: string;\r\n down: string;\r\n transactional?: boolean;\r\n}): Migration {\r\n return {\r\n version: migration.version,\r\n name: migration.name,\r\n up: migration.up,\r\n down: migration.down,\r\n transactional: migration.transactional,\r\n };\r\n}\r\n\r\n/**\r\n * Create a function-based migration for complex logic\r\n *\r\n * @example\r\n * ```typescript\r\n * export default createMigration({\r\n * version: '20240102000000',\r\n * name: 'seed_initial_data',\r\n * up: async (db) => {\r\n * await db.raw(`INSERT INTO users (email) VALUES ('admin@example.com')`);\r\n * await db.raw(`INSERT INTO settings (key, value) VALUES ('version', '1.0.0')`);\r\n * },\r\n * down: async (db) => {\r\n * await db.raw(`DELETE FROM settings WHERE key = 'version'`);\r\n * await db.raw(`DELETE FROM users WHERE email = 'admin@example.com'`);\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport function createMigration(migration: {\r\n version: string;\r\n name: string;\r\n up: (db: IMigrationDatabase) => Promise<void>;\r\n down: (db: IMigrationDatabase) => Promise<void>;\r\n transactional?: boolean;\r\n}): Migration {\r\n return {\r\n version: migration.version,\r\n name: migration.name,\r\n up: migration.up,\r\n down: migration.down,\r\n transactional: migration.transactional,\r\n };\r\n}\r\n\r\n/**\r\n * Type-safe migration definition with inference\r\n * Useful for defining migrations in separate files\r\n *\r\n * @example\r\n * ```typescript\r\n * // migrations/20240101000000_create_users.ts\r\n * export const migration = defineMigration({\r\n * version: '20240101000000',\r\n * name: 'create_users',\r\n * up: 'CREATE TABLE users (...)',\r\n * down: 'DROP TABLE users'\r\n * });\r\n *\r\n * // Or with functions\r\n * export const migration = defineMigration({\r\n * version: '20240102000000',\r\n * name: 'complex_migration',\r\n * up: async (db) => { ... },\r\n * down: async (db) => { ... }\r\n * });\r\n * ```\r\n */\r\nexport function defineMigration<\r\n T extends {\r\n version: string;\r\n name: string;\r\n up: string | ((db: IMigrationDatabase) => Promise<void>);\r\n down: string | ((db: IMigrationDatabase) => Promise<void>);\r\n transactional?: boolean;\r\n }\r\n>(migration: T): Migration {\r\n return migration;\r\n}\r\n\r\n/**\r\n * Generate a version timestamp for new migrations\r\n *\r\n * @example\r\n * ```typescript\r\n * const version = generateVersion(); // '20240315143052'\r\n * ```\r\n */\r\nexport function generateVersion(): string {\r\n const now = new Date();\r\n return [\r\n now.getFullYear(),\r\n String(now.getMonth() + 1).padStart(2, '0'),\r\n String(now.getDate()).padStart(2, '0'),\r\n String(now.getHours()).padStart(2, '0'),\r\n String(now.getMinutes()).padStart(2, '0'),\r\n String(now.getSeconds()).padStart(2, '0'),\r\n ].join('');\r\n}\r\n\r\n/**\r\n * Common SQL snippets for migrations\r\n */\r\nexport const SQL = {\r\n /**\r\n * Create updated_at trigger function (PostgreSQL)\r\n */\r\n createUpdatedAtFunction: `\r\n CREATE OR REPLACE FUNCTION update_updated_at_column()\r\n RETURNS TRIGGER AS $$\r\n BEGIN\r\n NEW.updated_at = CURRENT_TIMESTAMP;\r\n RETURN NEW;\r\n END;\r\n $$ language 'plpgsql';\r\n `,\r\n\r\n /**\r\n * Create an updated_at trigger for a table\r\n */\r\n createUpdatedAtTrigger: (tableName: string) => `\r\n CREATE TRIGGER update_${tableName}_updated_at\r\n BEFORE UPDATE ON \"${tableName}\"\r\n FOR EACH ROW\r\n EXECUTE FUNCTION update_updated_at_column();\r\n `,\r\n\r\n /**\r\n * Drop an updated_at trigger\r\n */\r\n dropUpdatedAtTrigger: (tableName: string) => `\r\n DROP TRIGGER IF EXISTS update_${tableName}_updated_at ON \"${tableName}\";\r\n `,\r\n\r\n /**\r\n * Standard timestamp columns\r\n */\r\n timestampColumns: `\r\n created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,\r\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL\r\n `,\r\n\r\n /**\r\n * UUID primary key with default\r\n */\r\n uuidPrimaryKey: `id UUID PRIMARY KEY DEFAULT gen_random_uuid()`,\r\n\r\n /**\r\n * Enable UUID extension\r\n */\r\n enableUuidExtension: `CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"`,\r\n\r\n /**\r\n * Enable pgcrypto for gen_random_uuid()\r\n */\r\n enablePgCrypto: `CREATE EXTENSION IF NOT EXISTS \"pgcrypto\"`,\r\n};\r\n","/**\n * Enterprise SSO and Multi-Tenancy Migrations\n *\n * These migrations set up the tables required for:\n * - OIDC/SSO configuration storage\n * - Domain verification\n * - Multi-tenant management\n * - Member management\n * - Usage tracking\n *\n * @example\n * ```typescript\n * import { Migrator, enterpriseMigrations } from '@digilogiclabs/platform-core';\n *\n * const migrator = new Migrator({\n * database: db,\n * migrations: [...enterpriseMigrations, ...yourMigrations],\n * });\n *\n * await migrator.up();\n * ```\n */\n\nimport type { Migration } from \"../interfaces/IMigration\";\n\n/**\n * SSO OIDC Configuration Table Migration\n */\nexport const createSsoOidcConfigsTable: Migration = {\n version: \"20241217_001\",\n name: \"create_sso_oidc_configs_table\",\n up: `\n CREATE TABLE IF NOT EXISTS sso_oidc_configs (\n tenant_id VARCHAR(255) PRIMARY KEY,\n issuer_url VARCHAR(500) NOT NULL,\n client_id VARCHAR(255) NOT NULL,\n client_secret VARCHAR(500) NOT NULL,\n authorization_endpoint VARCHAR(500),\n token_endpoint VARCHAR(500),\n userinfo_endpoint VARCHAR(500),\n jwks_uri VARCHAR(500),\n scopes JSONB DEFAULT '[\"openid\", \"profile\", \"email\"]',\n claim_mapping JSONB DEFAULT '{}',\n domains JSONB DEFAULT '[]',\n jit_provisioning_enabled BOOLEAN DEFAULT false,\n default_role VARCHAR(50) DEFAULT 'member',\n pkce_method VARCHAR(10) DEFAULT 'S256',\n metadata JSONB DEFAULT '{}',\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n );\n\n CREATE INDEX IF NOT EXISTS idx_sso_oidc_domains ON sso_oidc_configs USING GIN (domains);\n `,\n down: \"DROP TABLE IF EXISTS sso_oidc_configs CASCADE\",\n};\n\n/**\n * Domain Verifications Table Migration\n */\nexport const createDomainVerificationsTable: Migration = {\n version: \"20241217_002\",\n name: \"create_domain_verifications_table\",\n up: `\n CREATE TABLE IF NOT EXISTS domain_verifications (\n id SERIAL PRIMARY KEY,\n tenant_id VARCHAR(255) NOT NULL,\n domain VARCHAR(255) NOT NULL,\n verification_token VARCHAR(255) NOT NULL,\n verification_method VARCHAR(50) DEFAULT 'dns_txt',\n status VARCHAR(50) DEFAULT 'pending',\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n expires_at TIMESTAMP WITH TIME ZONE,\n verified_at TIMESTAMP WITH TIME ZONE,\n UNIQUE(tenant_id, domain)\n );\n\n CREATE INDEX IF NOT EXISTS idx_domain_verifications_status ON domain_verifications(status);\n `,\n down: \"DROP TABLE IF EXISTS domain_verifications CASCADE\",\n};\n\n/**\n * Verified Domains Table Migration\n */\nexport const createVerifiedDomainsTable: Migration = {\n version: \"20241217_003\",\n name: \"create_verified_domains_table\",\n up: `\n CREATE TABLE IF NOT EXISTS verified_domains (\n id SERIAL PRIMARY KEY,\n tenant_id VARCHAR(255) NOT NULL,\n domain VARCHAR(255) NOT NULL,\n verification_token VARCHAR(255),\n verified_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n UNIQUE(tenant_id, domain)\n );\n\n CREATE INDEX IF NOT EXISTS idx_verified_domains_domain ON verified_domains(domain);\n `,\n down: \"DROP TABLE IF EXISTS verified_domains CASCADE\",\n};\n\n/**\n * Tenants Table Migration\n */\nexport const createTenantsTable: Migration = {\n version: \"20241217_004\",\n name: \"create_tenants_table\",\n up: `\n CREATE TABLE IF NOT EXISTS tenants (\n id VARCHAR(255) PRIMARY KEY,\n slug VARCHAR(255) UNIQUE NOT NULL,\n name VARCHAR(255) NOT NULL,\n status VARCHAR(50) NOT NULL DEFAULT 'active',\n plan VARCHAR(100) NOT NULL,\n custom_domain VARCHAR(255),\n settings JSONB NOT NULL DEFAULT '{}',\n features JSONB NOT NULL DEFAULT '{}',\n quotas JSONB NOT NULL DEFAULT '{}',\n metadata JSONB NOT NULL DEFAULT '{}',\n isolation_model VARCHAR(50) NOT NULL DEFAULT 'row_level',\n schema_name VARCHAR(255),\n created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\n deleted_at TIMESTAMP WITH TIME ZONE\n );\n\n CREATE INDEX IF NOT EXISTS idx_tenants_slug ON tenants(slug);\n CREATE INDEX IF NOT EXISTS idx_tenants_custom_domain ON tenants(custom_domain);\n CREATE INDEX IF NOT EXISTS idx_tenants_status ON tenants(status);\n CREATE INDEX IF NOT EXISTS idx_tenants_plan ON tenants(plan);\n `,\n down: \"DROP TABLE IF EXISTS tenants CASCADE\",\n};\n\n/**\n * Tenant Members Table Migration\n */\nexport const createTenantMembersTable: Migration = {\n version: \"20241217_005\",\n name: \"create_tenant_members_table\",\n up: `\n CREATE TABLE IF NOT EXISTS tenant_members (\n id VARCHAR(255) PRIMARY KEY,\n tenant_id VARCHAR(255) NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,\n user_id VARCHAR(255) NOT NULL,\n role VARCHAR(50) NOT NULL DEFAULT 'member',\n permissions JSONB DEFAULT '[]',\n status VARCHAR(50) NOT NULL DEFAULT 'active',\n invited_by VARCHAR(255),\n joined_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\n UNIQUE(tenant_id, user_id)\n );\n\n CREATE INDEX IF NOT EXISTS idx_tenant_members_user_id ON tenant_members(user_id);\n CREATE INDEX IF NOT EXISTS idx_tenant_members_status ON tenant_members(status);\n `,\n down: \"DROP TABLE IF EXISTS tenant_members CASCADE\",\n};\n\n/**\n * Tenant Invitations Table Migration\n */\nexport const createTenantInvitationsTable: Migration = {\n version: \"20241217_006\",\n name: \"create_tenant_invitations_table\",\n up: `\n CREATE TABLE IF NOT EXISTS tenant_invitations (\n id VARCHAR(255) PRIMARY KEY,\n tenant_id VARCHAR(255) NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,\n email VARCHAR(255) NOT NULL,\n role VARCHAR(50) NOT NULL DEFAULT 'member',\n permissions JSONB DEFAULT '[]',\n token VARCHAR(255) UNIQUE NOT NULL,\n invited_by VARCHAR(255) NOT NULL,\n status VARCHAR(50) NOT NULL DEFAULT 'pending',\n message TEXT,\n created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\n expires_at TIMESTAMP WITH TIME ZONE NOT NULL,\n accepted_at TIMESTAMP WITH TIME ZONE\n );\n\n CREATE INDEX IF NOT EXISTS idx_tenant_invitations_email ON tenant_invitations(email);\n CREATE INDEX IF NOT EXISTS idx_tenant_invitations_token ON tenant_invitations(token);\n CREATE INDEX IF NOT EXISTS idx_tenant_invitations_status ON tenant_invitations(status);\n `,\n down: \"DROP TABLE IF EXISTS tenant_invitations CASCADE\",\n};\n\n/**\n * Tenant Usage Table Migration\n */\nexport const createTenantUsageTable: Migration = {\n version: \"20241217_007\",\n name: \"create_tenant_usage_table\",\n up: `\n CREATE TABLE IF NOT EXISTS tenant_usage (\n tenant_id VARCHAR(255) PRIMARY KEY REFERENCES tenants(id) ON DELETE CASCADE,\n user_count INTEGER NOT NULL DEFAULT 0,\n storage_used_bytes BIGINT NOT NULL DEFAULT 0,\n api_requests_this_month BIGINT NOT NULL DEFAULT 0,\n project_count INTEGER NOT NULL DEFAULT 0,\n custom JSONB DEFAULT '{}',\n updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()\n );\n `,\n down: \"DROP TABLE IF EXISTS tenant_usage CASCADE\",\n};\n\n/**\n * SSO Sessions Table Migration\n */\nexport const createSsoSessionsTable: Migration = {\n version: \"20241217_008\",\n name: \"create_sso_sessions_table\",\n up: `\n CREATE TABLE IF NOT EXISTS sso_sessions (\n id VARCHAR(255) PRIMARY KEY,\n user_id VARCHAR(255) NOT NULL,\n tenant_id VARCHAR(255) NOT NULL,\n sso_provider VARCHAR(50) NOT NULL,\n idp_session_id VARCHAR(255),\n saml_session_index VARCHAR(255),\n groups JSONB DEFAULT '[]',\n access_token TEXT,\n refresh_token TEXT,\n id_token TEXT,\n expires_at TIMESTAMP WITH TIME ZONE NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()\n );\n\n CREATE INDEX IF NOT EXISTS idx_sso_sessions_user_id ON sso_sessions(user_id);\n CREATE INDEX IF NOT EXISTS idx_sso_sessions_tenant_id ON sso_sessions(tenant_id);\n CREATE INDEX IF NOT EXISTS idx_sso_sessions_expires ON sso_sessions(expires_at);\n `,\n down: \"DROP TABLE IF EXISTS sso_sessions CASCADE\",\n};\n\n/**\n * All enterprise migrations in order\n */\nexport const enterpriseMigrations: Migration[] = [\n createSsoOidcConfigsTable,\n createDomainVerificationsTable,\n createVerifiedDomainsTable,\n createTenantsTable,\n createTenantMembersTable,\n createTenantInvitationsTable,\n createTenantUsageTable,\n createSsoSessionsTable,\n];\n\n/**\n * Get enterprise migrations for a specific feature\n */\nexport function getEnterpriseMigrations(features: {\n sso?: boolean;\n tenancy?: boolean;\n}): Migration[] {\n const migrations: Migration[] = [];\n\n if (features.sso) {\n migrations.push(\n createSsoOidcConfigsTable,\n createDomainVerificationsTable,\n createVerifiedDomainsTable,\n createSsoSessionsTable,\n );\n }\n\n if (features.tenancy) {\n migrations.push(\n createTenantsTable,\n createTenantMembersTable,\n createTenantInvitationsTable,\n createTenantUsageTable,\n );\n }\n\n return migrations;\n}\n"],"mappings":"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","names":["module"]}
1
+ {"version":3,"sources":["../../src/migrations/index.ts","../../src/migrations/Migrator.ts","../../src/migrations/helpers.ts","../../src/migrations/enterprise.ts"],"sourcesContent":["/**\n * Database Migrations\n *\n * Enterprise-grade migration system for managing database schema changes.\n *\n * @example\n * ```typescript\n * import { Migrator } from '@digilogiclabs/platform-core';\n * import { PostgresDatabase } from '@digilogiclabs/platform-core';\n *\n * // Create database connection\n * const db = await PostgresDatabase.fromEnv();\n *\n * // Create migrator\n * const migrator = new Migrator(db, {\n * tableName: '_migrations',\n * migrationsDir: './migrations'\n * });\n *\n * // Add migrations programmatically\n * migrator.addMigrations([\n * {\n * version: '20240101000000',\n * name: 'create_users_table',\n * up: `CREATE TABLE users (id UUID PRIMARY KEY, email VARCHAR(255) UNIQUE)`,\n * down: `DROP TABLE users`\n * }\n * ]);\n *\n * // Or load from directory\n * await migrator.loadMigrations('./migrations');\n *\n * // Check status\n * const status = await migrator.status();\n * console.log('Applied:', status.applied.length);\n * console.log('Pending:', status.pending.length);\n *\n * // Run pending migrations\n * const results = await migrator.up();\n * for (const result of results) {\n * if (result.success) {\n * console.log(`✓ ${result.migration.name} (${result.executionTime}ms)`);\n * } else {\n * console.error(`✗ ${result.migration.name}: ${result.error?.message}`);\n * }\n * }\n *\n * // Rollback last migration\n * await migrator.down();\n *\n * // Rollback last 3 migrations\n * await migrator.down({ steps: 3 });\n *\n * // Dry run (preview without applying)\n * await migrator.up({ dryRun: true });\n * ```\n */\n\nexport { Migrator } from \"./Migrator\";\nexport type {\n Migration,\n MigrationRecord,\n MigrationResult,\n MigrationStatus,\n MigratorConfig,\n IMigrator,\n IMigrationDatabase,\n} from \"../interfaces/IMigration\";\n\n// Re-export common migration patterns\nexport { createMigration, defineMigration, sqlMigration } from \"./helpers\";\n\n// Enterprise migrations for SSO and multi-tenancy\nexport {\n enterpriseMigrations,\n getEnterpriseMigrations,\n createSsoOidcConfigsTable,\n createDomainVerificationsTable,\n createVerifiedDomainsTable,\n createTenantsTable,\n createTenantMembersTable,\n createTenantInvitationsTable,\n createTenantUsageTable,\n createSsoSessionsTable,\n} from \"./enterprise\";\n","/**\n * Database Migrator\n *\n * Enterprise-grade database migration system supporting:\n * - PostgreSQL (primary)\n * - Memory database (for testing)\n * - Transaction-safe migrations\n * - Concurrent execution locking\n * - Checksum validation\n * - Dry-run mode\n */\n\nimport type {\n IMigrator,\n Migration,\n MigrationRecord,\n MigrationResult,\n MigrationStatus,\n MigratorConfig,\n IMigrationDatabase,\n} from \"../interfaces/IMigration\";\n\nconst DEFAULT_CONFIG: Required<Omit<MigratorConfig, \"migrationsDir\">> & {\n migrationsDir?: string;\n} = {\n tableName: \"_migrations\",\n schema: \"public\",\n lockTimeout: 60,\n validateChecksums: true,\n migrationsDir: undefined,\n};\n\n/**\n * Generate a checksum for migration content\n */\nfunction generateChecksum(content: string): string {\n // Simple hash for checksum - in production you might use crypto\n let hash = 0;\n for (let i = 0; i < content.length; i++) {\n const char = content.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32-bit integer\n }\n return Math.abs(hash).toString(16).padStart(8, \"0\");\n}\n\n/**\n * Sort migrations by version\n */\nfunction sortMigrations(migrations: Migration[]): Migration[] {\n return [...migrations].sort((a, b) => a.version.localeCompare(b.version));\n}\n\nexport class Migrator implements IMigrator {\n private db: IMigrationDatabase;\n private config: Required<Omit<MigratorConfig, \"migrationsDir\">> & {\n migrationsDir?: string;\n };\n private migrations: Migration[] = [];\n private initialized = false;\n private locked = false;\n\n constructor(db: IMigrationDatabase, config: MigratorConfig = {}) {\n this.db = db;\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n /**\n * Get the fully qualified migration table name\n */\n private get tableName(): string {\n return `\"${this.config.schema}\".\"${this.config.tableName}\"`;\n }\n\n /**\n * Get the lock table name\n */\n private get lockTableName(): string {\n return `\"${this.config.schema}\".\"${this.config.tableName}_lock\"`;\n }\n\n /**\n * Initialize migration tracking tables\n */\n private async initialize(): Promise<void> {\n if (this.initialized) return;\n\n // Create schema if not exists\n await this.db.raw(`CREATE SCHEMA IF NOT EXISTS \"${this.config.schema}\"`);\n\n // Create migrations tracking table\n await this.db.raw(`\n CREATE TABLE IF NOT EXISTS ${this.tableName} (\n version VARCHAR(255) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n applied_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,\n execution_time INTEGER NOT NULL,\n checksum VARCHAR(64)\n )\n `);\n\n // Create lock table for concurrent safety\n await this.db.raw(`\n CREATE TABLE IF NOT EXISTS ${this.lockTableName} (\n id INTEGER PRIMARY KEY DEFAULT 1,\n locked_at TIMESTAMP WITH TIME ZONE,\n locked_by VARCHAR(255),\n CONSTRAINT single_row CHECK (id = 1)\n )\n `);\n\n // Insert initial lock row if not exists\n await this.db.raw(`\n INSERT INTO ${this.lockTableName} (id, locked_at, locked_by)\n VALUES (1, NULL, NULL)\n ON CONFLICT (id) DO NOTHING\n `);\n\n this.initialized = true;\n }\n\n /**\n * Acquire migration lock\n */\n async lock(): Promise<boolean> {\n await this.initialize();\n\n const lockId = `${process.pid}-${Date.now()}`;\n const lockTimeout = new Date(Date.now() - this.config.lockTimeout * 1000);\n\n // Try to acquire lock (only if not locked or lock expired)\n const result = await this.db.raw<{ locked_at: Date | null }>(\n `\n UPDATE ${this.lockTableName}\n SET locked_at = CURRENT_TIMESTAMP, locked_by = $1\n WHERE id = 1 AND (locked_at IS NULL OR locked_at < $2)\n RETURNING locked_at\n `,\n [lockId, lockTimeout],\n );\n\n if (result.data.length > 0) {\n this.locked = true;\n return true;\n }\n\n return false;\n }\n\n /**\n * Release migration lock\n */\n async unlock(): Promise<void> {\n if (!this.locked) return;\n\n await this.db.raw(\n `\n UPDATE ${this.lockTableName}\n SET locked_at = NULL, locked_by = NULL\n WHERE id = 1\n `,\n );\n\n this.locked = false;\n }\n\n /**\n * Add migrations to the migrator\n */\n addMigrations(migrations: Migration[]): void {\n for (const migration of migrations) {\n // Generate checksum if not provided\n if (!migration.checksum) {\n const content =\n typeof migration.up === \"string\"\n ? migration.up\n : migration.up.toString();\n migration.checksum = generateChecksum(content);\n }\n\n // Avoid duplicates\n if (!this.migrations.find((m) => m.version === migration.version)) {\n this.migrations.push(migration);\n }\n }\n }\n\n /**\n * Load migrations from directory\n * Expects files named: {version}_{name}.ts or {version}_{name}.sql\n */\n async loadMigrations(dir: string): Promise<void> {\n // Dynamic import for Node.js file system\n const { readdir, readFile } = await import(\"fs/promises\");\n const { join } = await import(\"path\");\n\n const files = await readdir(dir);\n const migrationFiles = files.filter((f) =>\n f.match(/^\\d+_.*\\.(ts|js|sql)$/),\n );\n\n for (const file of migrationFiles) {\n const filePath = join(dir, file);\n const [version, ...nameParts] = file\n .replace(/\\.(ts|js|sql)$/, \"\")\n .split(\"_\");\n const name = nameParts.join(\"_\");\n\n if (file.endsWith(\".sql\")) {\n // SQL file - parse UP and DOWN sections\n const content = await readFile(filePath, \"utf-8\");\n const [up, down] = this.parseSqlMigration(content);\n\n this.addMigrations([\n {\n version: version!,\n name,\n up,\n down,\n },\n ]);\n } else {\n // TypeScript/JavaScript file - import the module\n const module = await import(filePath);\n this.addMigrations([\n {\n version: version!,\n name,\n up: module.up,\n down: module.down,\n transactional: module.transactional,\n },\n ]);\n }\n }\n }\n\n /**\n * Parse SQL migration file with -- UP and -- DOWN sections\n */\n private parseSqlMigration(content: string): [string, string] {\n const upMatch = content.match(/--\\s*UP\\s*\\n([\\s\\S]*?)(?=--\\s*DOWN|$)/i);\n const downMatch = content.match(/--\\s*DOWN\\s*\\n([\\s\\S]*?)$/i);\n\n const up = upMatch?.[1]?.trim() ?? content.trim();\n const down = downMatch?.[1]?.trim() ?? \"\";\n\n return [up, down];\n }\n\n /**\n * Get current migration status\n */\n async status(): Promise<MigrationStatus> {\n await this.initialize();\n\n // Get applied migrations\n const result = await this.db.raw<{\n version: string;\n name: string;\n applied_at: Date;\n execution_time: number;\n checksum: string | null;\n }>(\n `SELECT version, name, applied_at, execution_time, checksum\n FROM ${this.tableName}\n ORDER BY version ASC`,\n );\n\n const applied: MigrationRecord[] = result.data.map((row) => ({\n version: row.version,\n name: row.name,\n appliedAt: new Date(row.applied_at),\n executionTime: row.execution_time,\n checksum: row.checksum ?? undefined,\n }));\n\n const appliedVersions = new Set(applied.map((m) => m.version));\n const sortedMigrations = sortMigrations(this.migrations);\n\n const pending = sortedMigrations.filter(\n (m) => !appliedVersions.has(m.version),\n );\n\n return {\n applied,\n pending,\n currentVersion:\n applied.length > 0 ? applied[applied.length - 1]!.version : null,\n latestVersion:\n sortedMigrations.length > 0\n ? sortedMigrations[sortedMigrations.length - 1]!.version\n : null,\n };\n }\n\n /**\n * Run all pending migrations (or up to a specific version)\n */\n async up(\n options: { dryRun?: boolean; to?: string } = {},\n ): Promise<MigrationResult[]> {\n const { dryRun = false, to } = options;\n const results: MigrationResult[] = [];\n\n if (!dryRun) {\n const acquired = await this.lock();\n if (!acquired) {\n throw new Error(\n \"Could not acquire migration lock. Another migration may be in progress.\",\n );\n }\n }\n\n try {\n const status = await this.status();\n let pending = status.pending;\n\n // Filter to specific version if requested\n if (to) {\n const targetIndex = pending.findIndex((m) => m.version === to);\n if (targetIndex === -1) {\n throw new Error(\n `Target version ${to} not found in pending migrations`,\n );\n }\n pending = pending.slice(0, targetIndex + 1);\n }\n\n for (const migration of pending) {\n const result = await this.runMigration(migration, \"up\", dryRun);\n results.push(result);\n\n if (!result.success) {\n break; // Stop on first failure\n }\n }\n } finally {\n if (!dryRun) {\n await this.unlock();\n }\n }\n\n return results;\n }\n\n /**\n * Rollback migrations\n */\n async down(\n options: { dryRun?: boolean; steps?: number } = {},\n ): Promise<MigrationResult[]> {\n const { dryRun = false, steps = 1 } = options;\n const results: MigrationResult[] = [];\n\n if (!dryRun) {\n const acquired = await this.lock();\n if (!acquired) {\n throw new Error(\n \"Could not acquire migration lock. Another migration may be in progress.\",\n );\n }\n }\n\n try {\n const status = await this.status();\n\n // Get the last N applied migrations (in reverse order)\n const toRollback = status.applied.slice(-steps).reverse();\n\n for (const record of toRollback) {\n const migration = this.migrations.find(\n (m) => m.version === record.version,\n );\n if (!migration) {\n throw new Error(\n `Migration ${record.version} was applied but is not registered. Cannot rollback.`,\n );\n }\n\n const result = await this.runMigration(migration, \"down\", dryRun);\n results.push(result);\n\n if (!result.success) {\n break;\n }\n }\n } finally {\n if (!dryRun) {\n await this.unlock();\n }\n }\n\n return results;\n }\n\n /**\n * Rollback all migrations and re-run them\n */\n async reset(options: { dryRun?: boolean } = {}): Promise<MigrationResult[]> {\n const status = await this.status();\n const downResults = await this.down({\n dryRun: options.dryRun,\n steps: status.applied.length,\n });\n\n // Only proceed with up if all downs succeeded\n if (downResults.every((r) => r.success)) {\n const upResults = await this.up({ dryRun: options.dryRun });\n return [...downResults, ...upResults];\n }\n\n return downResults;\n }\n\n /**\n * Migrate to a specific version\n */\n async goto(\n version: string,\n options: { dryRun?: boolean } = {},\n ): Promise<MigrationResult[]> {\n const status = await this.status();\n const currentVersion = status.currentVersion;\n const results: MigrationResult[] = [];\n\n // If already at target, nothing to do\n if (currentVersion === version) {\n return results;\n }\n\n // Determine direction\n const isUp = !currentVersion || version > currentVersion;\n\n if (isUp) {\n return this.up({ ...options, to: version });\n } else {\n // Find how many steps down we need to go\n const currentIndex = status.applied.findIndex(\n (m) => m.version === currentVersion,\n );\n const targetIndex = status.applied.findIndex(\n (m) => m.version === version,\n );\n\n if (targetIndex === -1) {\n throw new Error(\n `Target version ${version} not found in applied migrations`,\n );\n }\n\n const steps = currentIndex - targetIndex;\n return this.down({ ...options, steps });\n }\n }\n\n /**\n * Run a single migration\n */\n private async runMigration(\n migration: Migration,\n direction: \"up\" | \"down\",\n dryRun: boolean,\n ): Promise<MigrationResult> {\n const startTime = Date.now();\n const action = direction === \"up\" ? migration.up : migration.down;\n\n try {\n if (dryRun) {\n // Just simulate - don't actually run\n return {\n migration,\n success: true,\n executionTime: 0,\n dryRun: true,\n };\n }\n\n const transactional = migration.transactional !== false;\n const runAction = async (db: IMigrationDatabase) => {\n if (typeof action === \"string\") {\n const result = await db.raw(action);\n if (result.error) {\n throw result.error;\n }\n } else {\n await action(db);\n }\n };\n\n if (transactional) {\n await this.db.transaction(async (tx) => {\n await runAction(tx);\n });\n } else {\n await runAction(this.db);\n }\n\n const executionTime = Date.now() - startTime;\n\n // Update tracking table\n if (direction === \"up\") {\n await this.db.raw(\n `INSERT INTO ${this.tableName} (version, name, execution_time, checksum)\n VALUES ($1, $2, $3, $4)`,\n [\n migration.version,\n migration.name,\n executionTime,\n migration.checksum,\n ],\n );\n } else {\n await this.db.raw(`DELETE FROM ${this.tableName} WHERE version = $1`, [\n migration.version,\n ]);\n }\n\n return {\n migration,\n success: true,\n executionTime,\n dryRun: false,\n };\n } catch (error) {\n return {\n migration,\n success: false,\n executionTime: Date.now() - startTime,\n error: error instanceof Error ? error : new Error(String(error)),\n dryRun: false,\n };\n }\n }\n\n /**\n * Create a new migration file\n */\n async create(name: string): Promise<string> {\n const { writeFile, mkdir } = await import(\"fs/promises\");\n const { join } = await import(\"path\");\n\n if (!this.config.migrationsDir) {\n throw new Error(\"migrationsDir must be configured to create migrations\");\n }\n\n // Ensure directory exists\n await mkdir(this.config.migrationsDir, { recursive: true });\n\n // Generate version timestamp\n const now = new Date();\n const version = [\n now.getFullYear(),\n String(now.getMonth() + 1).padStart(2, \"0\"),\n String(now.getDate()).padStart(2, \"0\"),\n String(now.getHours()).padStart(2, \"0\"),\n String(now.getMinutes()).padStart(2, \"0\"),\n String(now.getSeconds()).padStart(2, \"0\"),\n ].join(\"\");\n\n const safeName = name.replace(/[^a-zA-Z0-9_]/g, \"_\").toLowerCase();\n const fileName = `${version}_${safeName}.sql`;\n const filePath = join(this.config.migrationsDir, fileName);\n\n const template = `-- Migration: ${name}\n-- Version: ${version}\n-- Created: ${now.toISOString()}\n\n-- UP\n-- Add your forward migration SQL here\n\n\n-- DOWN\n-- Add your rollback migration SQL here\n\n`;\n\n await writeFile(filePath, template, \"utf-8\");\n\n return filePath;\n }\n\n /**\n * Validate migration integrity\n */\n async validate(): Promise<{ valid: boolean; errors: string[] }> {\n const errors: string[] = [];\n const status = await this.status();\n\n if (!this.config.validateChecksums) {\n return { valid: true, errors };\n }\n\n for (const applied of status.applied) {\n const migration = this.migrations.find(\n (m) => m.version === applied.version,\n );\n\n if (!migration) {\n errors.push(\n `Migration ${applied.version} (${applied.name}) was applied but is not registered`,\n );\n continue;\n }\n\n if (applied.checksum && migration.checksum !== applied.checksum) {\n errors.push(\n `Migration ${applied.version} (${applied.name}) has been modified since it was applied`,\n );\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n }\n}\n","/**\n * Migration Helper Functions\n *\n * Utilities for creating migrations in a type-safe and convenient way.\n */\n\nimport type { Migration, IMigrationDatabase } from \"../interfaces/IMigration\";\n\n/**\n * Create a SQL-based migration\n *\n * @example\n * ```typescript\n * export default sqlMigration({\n * version: '20240101000000',\n * name: 'create_users',\n * up: `\n * CREATE TABLE users (\n * id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n * email VARCHAR(255) UNIQUE NOT NULL,\n * created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n * )\n * `,\n * down: `DROP TABLE users`\n * });\n * ```\n */\nexport function sqlMigration(migration: {\n version: string;\n name: string;\n up: string;\n down: string;\n transactional?: boolean;\n}): Migration {\n return {\n version: migration.version,\n name: migration.name,\n up: migration.up,\n down: migration.down,\n transactional: migration.transactional,\n };\n}\n\n/**\n * Create a function-based migration for complex logic\n *\n * @example\n * ```typescript\n * export default createMigration({\n * version: '20240102000000',\n * name: 'seed_initial_data',\n * up: async (db) => {\n * await db.raw(`INSERT INTO users (email) VALUES ('admin@example.com')`);\n * await db.raw(`INSERT INTO settings (key, value) VALUES ('version', '1.0.0')`);\n * },\n * down: async (db) => {\n * await db.raw(`DELETE FROM settings WHERE key = 'version'`);\n * await db.raw(`DELETE FROM users WHERE email = 'admin@example.com'`);\n * }\n * });\n * ```\n */\nexport function createMigration(migration: {\n version: string;\n name: string;\n up: (db: IMigrationDatabase) => Promise<void>;\n down: (db: IMigrationDatabase) => Promise<void>;\n transactional?: boolean;\n}): Migration {\n return {\n version: migration.version,\n name: migration.name,\n up: migration.up,\n down: migration.down,\n transactional: migration.transactional,\n };\n}\n\n/**\n * Type-safe migration definition with inference\n * Useful for defining migrations in separate files\n *\n * @example\n * ```typescript\n * // migrations/20240101000000_create_users.ts\n * export const migration = defineMigration({\n * version: '20240101000000',\n * name: 'create_users',\n * up: 'CREATE TABLE users (...)',\n * down: 'DROP TABLE users'\n * });\n *\n * // Or with functions\n * export const migration = defineMigration({\n * version: '20240102000000',\n * name: 'complex_migration',\n * up: async (db) => { ... },\n * down: async (db) => { ... }\n * });\n * ```\n */\nexport function defineMigration<\n T extends {\n version: string;\n name: string;\n up: string | ((db: IMigrationDatabase) => Promise<void>);\n down: string | ((db: IMigrationDatabase) => Promise<void>);\n transactional?: boolean;\n },\n>(migration: T): Migration {\n return migration;\n}\n\n/**\n * Generate a version timestamp for new migrations\n *\n * @example\n * ```typescript\n * const version = generateVersion(); // '20240315143052'\n * ```\n */\nexport function generateVersion(): string {\n const now = new Date();\n return [\n now.getFullYear(),\n String(now.getMonth() + 1).padStart(2, \"0\"),\n String(now.getDate()).padStart(2, \"0\"),\n String(now.getHours()).padStart(2, \"0\"),\n String(now.getMinutes()).padStart(2, \"0\"),\n String(now.getSeconds()).padStart(2, \"0\"),\n ].join(\"\");\n}\n\n/**\n * Common SQL snippets for migrations\n */\nexport const SQL = {\n /**\n * Create updated_at trigger function (PostgreSQL)\n */\n createUpdatedAtFunction: `\n CREATE OR REPLACE FUNCTION update_updated_at_column()\n RETURNS TRIGGER AS $$\n BEGIN\n NEW.updated_at = CURRENT_TIMESTAMP;\n RETURN NEW;\n END;\n $$ language 'plpgsql';\n `,\n\n /**\n * Create an updated_at trigger for a table\n */\n createUpdatedAtTrigger: (tableName: string) => `\n CREATE TRIGGER update_${tableName}_updated_at\n BEFORE UPDATE ON \"${tableName}\"\n FOR EACH ROW\n EXECUTE FUNCTION update_updated_at_column();\n `,\n\n /**\n * Drop an updated_at trigger\n */\n dropUpdatedAtTrigger: (tableName: string) => `\n DROP TRIGGER IF EXISTS update_${tableName}_updated_at ON \"${tableName}\";\n `,\n\n /**\n * Standard timestamp columns\n */\n timestampColumns: `\n created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL\n `,\n\n /**\n * UUID primary key with default\n */\n uuidPrimaryKey: `id UUID PRIMARY KEY DEFAULT gen_random_uuid()`,\n\n /**\n * Enable UUID extension\n */\n enableUuidExtension: `CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"`,\n\n /**\n * Enable pgcrypto for gen_random_uuid()\n */\n enablePgCrypto: `CREATE EXTENSION IF NOT EXISTS \"pgcrypto\"`,\n};\n","/**\n * Enterprise SSO and Multi-Tenancy Migrations\n *\n * These migrations set up the tables required for:\n * - OIDC/SSO configuration storage\n * - Domain verification\n * - Multi-tenant management\n * - Member management\n * - Usage tracking\n *\n * @example\n * ```typescript\n * import { Migrator, enterpriseMigrations } from '@digilogiclabs/platform-core';\n *\n * const migrator = new Migrator({\n * database: db,\n * migrations: [...enterpriseMigrations, ...yourMigrations],\n * });\n *\n * await migrator.up();\n * ```\n */\n\nimport type { Migration } from \"../interfaces/IMigration\";\n\n/**\n * SSO OIDC Configuration Table Migration\n */\nexport const createSsoOidcConfigsTable: Migration = {\n version: \"20241217_001\",\n name: \"create_sso_oidc_configs_table\",\n up: `\n CREATE TABLE IF NOT EXISTS sso_oidc_configs (\n tenant_id VARCHAR(255) PRIMARY KEY,\n issuer_url VARCHAR(500) NOT NULL,\n client_id VARCHAR(255) NOT NULL,\n client_secret VARCHAR(500) NOT NULL,\n authorization_endpoint VARCHAR(500),\n token_endpoint VARCHAR(500),\n userinfo_endpoint VARCHAR(500),\n jwks_uri VARCHAR(500),\n scopes JSONB DEFAULT '[\"openid\", \"profile\", \"email\"]',\n claim_mapping JSONB DEFAULT '{}',\n domains JSONB DEFAULT '[]',\n jit_provisioning_enabled BOOLEAN DEFAULT false,\n default_role VARCHAR(50) DEFAULT 'member',\n pkce_method VARCHAR(10) DEFAULT 'S256',\n metadata JSONB DEFAULT '{}',\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n );\n\n CREATE INDEX IF NOT EXISTS idx_sso_oidc_domains ON sso_oidc_configs USING GIN (domains);\n `,\n down: \"DROP TABLE IF EXISTS sso_oidc_configs CASCADE\",\n};\n\n/**\n * Domain Verifications Table Migration\n */\nexport const createDomainVerificationsTable: Migration = {\n version: \"20241217_002\",\n name: \"create_domain_verifications_table\",\n up: `\n CREATE TABLE IF NOT EXISTS domain_verifications (\n id SERIAL PRIMARY KEY,\n tenant_id VARCHAR(255) NOT NULL,\n domain VARCHAR(255) NOT NULL,\n verification_token VARCHAR(255) NOT NULL,\n verification_method VARCHAR(50) DEFAULT 'dns_txt',\n status VARCHAR(50) DEFAULT 'pending',\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n expires_at TIMESTAMP WITH TIME ZONE,\n verified_at TIMESTAMP WITH TIME ZONE,\n UNIQUE(tenant_id, domain)\n );\n\n CREATE INDEX IF NOT EXISTS idx_domain_verifications_status ON domain_verifications(status);\n `,\n down: \"DROP TABLE IF EXISTS domain_verifications CASCADE\",\n};\n\n/**\n * Verified Domains Table Migration\n */\nexport const createVerifiedDomainsTable: Migration = {\n version: \"20241217_003\",\n name: \"create_verified_domains_table\",\n up: `\n CREATE TABLE IF NOT EXISTS verified_domains (\n id SERIAL PRIMARY KEY,\n tenant_id VARCHAR(255) NOT NULL,\n domain VARCHAR(255) NOT NULL,\n verification_token VARCHAR(255),\n verified_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n UNIQUE(tenant_id, domain)\n );\n\n CREATE INDEX IF NOT EXISTS idx_verified_domains_domain ON verified_domains(domain);\n `,\n down: \"DROP TABLE IF EXISTS verified_domains CASCADE\",\n};\n\n/**\n * Tenants Table Migration\n */\nexport const createTenantsTable: Migration = {\n version: \"20241217_004\",\n name: \"create_tenants_table\",\n up: `\n CREATE TABLE IF NOT EXISTS tenants (\n id VARCHAR(255) PRIMARY KEY,\n slug VARCHAR(255) UNIQUE NOT NULL,\n name VARCHAR(255) NOT NULL,\n status VARCHAR(50) NOT NULL DEFAULT 'active',\n plan VARCHAR(100) NOT NULL,\n custom_domain VARCHAR(255),\n settings JSONB NOT NULL DEFAULT '{}',\n features JSONB NOT NULL DEFAULT '{}',\n quotas JSONB NOT NULL DEFAULT '{}',\n metadata JSONB NOT NULL DEFAULT '{}',\n isolation_model VARCHAR(50) NOT NULL DEFAULT 'row_level',\n schema_name VARCHAR(255),\n created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\n deleted_at TIMESTAMP WITH TIME ZONE\n );\n\n CREATE INDEX IF NOT EXISTS idx_tenants_slug ON tenants(slug);\n CREATE INDEX IF NOT EXISTS idx_tenants_custom_domain ON tenants(custom_domain);\n CREATE INDEX IF NOT EXISTS idx_tenants_status ON tenants(status);\n CREATE INDEX IF NOT EXISTS idx_tenants_plan ON tenants(plan);\n `,\n down: \"DROP TABLE IF EXISTS tenants CASCADE\",\n};\n\n/**\n * Tenant Members Table Migration\n */\nexport const createTenantMembersTable: Migration = {\n version: \"20241217_005\",\n name: \"create_tenant_members_table\",\n up: `\n CREATE TABLE IF NOT EXISTS tenant_members (\n id VARCHAR(255) PRIMARY KEY,\n tenant_id VARCHAR(255) NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,\n user_id VARCHAR(255) NOT NULL,\n role VARCHAR(50) NOT NULL DEFAULT 'member',\n permissions JSONB DEFAULT '[]',\n status VARCHAR(50) NOT NULL DEFAULT 'active',\n invited_by VARCHAR(255),\n joined_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\n UNIQUE(tenant_id, user_id)\n );\n\n CREATE INDEX IF NOT EXISTS idx_tenant_members_user_id ON tenant_members(user_id);\n CREATE INDEX IF NOT EXISTS idx_tenant_members_status ON tenant_members(status);\n `,\n down: \"DROP TABLE IF EXISTS tenant_members CASCADE\",\n};\n\n/**\n * Tenant Invitations Table Migration\n */\nexport const createTenantInvitationsTable: Migration = {\n version: \"20241217_006\",\n name: \"create_tenant_invitations_table\",\n up: `\n CREATE TABLE IF NOT EXISTS tenant_invitations (\n id VARCHAR(255) PRIMARY KEY,\n tenant_id VARCHAR(255) NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,\n email VARCHAR(255) NOT NULL,\n role VARCHAR(50) NOT NULL DEFAULT 'member',\n permissions JSONB DEFAULT '[]',\n token VARCHAR(255) UNIQUE NOT NULL,\n invited_by VARCHAR(255) NOT NULL,\n status VARCHAR(50) NOT NULL DEFAULT 'pending',\n message TEXT,\n created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\n expires_at TIMESTAMP WITH TIME ZONE NOT NULL,\n accepted_at TIMESTAMP WITH TIME ZONE\n );\n\n CREATE INDEX IF NOT EXISTS idx_tenant_invitations_email ON tenant_invitations(email);\n CREATE INDEX IF NOT EXISTS idx_tenant_invitations_token ON tenant_invitations(token);\n CREATE INDEX IF NOT EXISTS idx_tenant_invitations_status ON tenant_invitations(status);\n `,\n down: \"DROP TABLE IF EXISTS tenant_invitations CASCADE\",\n};\n\n/**\n * Tenant Usage Table Migration\n */\nexport const createTenantUsageTable: Migration = {\n version: \"20241217_007\",\n name: \"create_tenant_usage_table\",\n up: `\n CREATE TABLE IF NOT EXISTS tenant_usage (\n tenant_id VARCHAR(255) PRIMARY KEY REFERENCES tenants(id) ON DELETE CASCADE,\n user_count INTEGER NOT NULL DEFAULT 0,\n storage_used_bytes BIGINT NOT NULL DEFAULT 0,\n api_requests_this_month BIGINT NOT NULL DEFAULT 0,\n project_count INTEGER NOT NULL DEFAULT 0,\n custom JSONB DEFAULT '{}',\n updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()\n );\n `,\n down: \"DROP TABLE IF EXISTS tenant_usage CASCADE\",\n};\n\n/**\n * SSO Sessions Table Migration\n */\nexport const createSsoSessionsTable: Migration = {\n version: \"20241217_008\",\n name: \"create_sso_sessions_table\",\n up: `\n CREATE TABLE IF NOT EXISTS sso_sessions (\n id VARCHAR(255) PRIMARY KEY,\n user_id VARCHAR(255) NOT NULL,\n tenant_id VARCHAR(255) NOT NULL,\n sso_provider VARCHAR(50) NOT NULL,\n idp_session_id VARCHAR(255),\n saml_session_index VARCHAR(255),\n groups JSONB DEFAULT '[]',\n access_token TEXT,\n refresh_token TEXT,\n id_token TEXT,\n expires_at TIMESTAMP WITH TIME ZONE NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()\n );\n\n CREATE INDEX IF NOT EXISTS idx_sso_sessions_user_id ON sso_sessions(user_id);\n CREATE INDEX IF NOT EXISTS idx_sso_sessions_tenant_id ON sso_sessions(tenant_id);\n CREATE INDEX IF NOT EXISTS idx_sso_sessions_expires ON sso_sessions(expires_at);\n `,\n down: \"DROP TABLE IF EXISTS sso_sessions CASCADE\",\n};\n\n/**\n * All enterprise migrations in order\n */\nexport const enterpriseMigrations: Migration[] = [\n createSsoOidcConfigsTable,\n createDomainVerificationsTable,\n createVerifiedDomainsTable,\n createTenantsTable,\n createTenantMembersTable,\n createTenantInvitationsTable,\n createTenantUsageTable,\n createSsoSessionsTable,\n];\n\n/**\n * Get enterprise migrations for a specific feature\n */\nexport function getEnterpriseMigrations(features: {\n sso?: boolean;\n tenancy?: boolean;\n}): Migration[] {\n const migrations: Migration[] = [];\n\n if (features.sso) {\n migrations.push(\n createSsoOidcConfigsTable,\n createDomainVerificationsTable,\n createVerifiedDomainsTable,\n createSsoSessionsTable,\n );\n }\n\n if (features.tenancy) {\n migrations.push(\n createTenantsTable,\n createTenantMembersTable,\n createTenantInvitationsTable,\n createTenantUsageTable,\n );\n }\n\n return migrations;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACsBA,IAAM,iBAEF;AAAA,EACF,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,eAAe;AACjB;AAKA,SAAS,iBAAiB,SAAyB;AAEjD,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,OAAO,QAAQ,WAAW,CAAC;AACjC,YAAQ,QAAQ,KAAK,OAAO;AAC5B,WAAO,OAAO;AAAA,EAChB;AACA,SAAO,KAAK,IAAI,IAAI,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AACpD;AAKA,SAAS,eAAe,YAAsC;AAC5D,SAAO,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,cAAc,EAAE,OAAO,CAAC;AAC1E;AAEO,IAAM,WAAN,MAAoC;AAAA,EACjC;AAAA,EACA;AAAA,EAGA,aAA0B,CAAC;AAAA,EAC3B,cAAc;AAAA,EACd,SAAS;AAAA,EAEjB,YAAY,IAAwB,SAAyB,CAAC,GAAG;AAC/D,SAAK,KAAK;AACV,SAAK,SAAS,EAAE,GAAG,gBAAgB,GAAG,OAAO;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAY,YAAoB;AAC9B,WAAO,IAAI,KAAK,OAAO,MAAM,MAAM,KAAK,OAAO,SAAS;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKA,IAAY,gBAAwB;AAClC,WAAO,IAAI,KAAK,OAAO,MAAM,MAAM,KAAK,OAAO,SAAS;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,aAA4B;AACxC,QAAI,KAAK,YAAa;AAGtB,UAAM,KAAK,GAAG,IAAI,gCAAgC,KAAK,OAAO,MAAM,GAAG;AAGvE,UAAM,KAAK,GAAG,IAAI;AAAA,mCACa,KAAK,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAO5C;AAGD,UAAM,KAAK,GAAG,IAAI;AAAA,mCACa,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAMhD;AAGD,UAAM,KAAK,GAAG,IAAI;AAAA,oBACF,KAAK,aAAa;AAAA;AAAA;AAAA,KAGjC;AAED,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAyB;AAC7B,UAAM,KAAK,WAAW;AAEtB,UAAM,SAAS,GAAG,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;AAC3C,UAAM,cAAc,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,OAAO,cAAc,GAAI;AAGxE,UAAM,SAAS,MAAM,KAAK,GAAG;AAAA,MAC3B;AAAA,eACS,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,MAK3B,CAAC,QAAQ,WAAW;AAAA,IACtB;AAEA,QAAI,OAAO,KAAK,SAAS,GAAG;AAC1B,WAAK,SAAS;AACd,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAwB;AAC5B,QAAI,CAAC,KAAK,OAAQ;AAElB,UAAM,KAAK,GAAG;AAAA,MACZ;AAAA,eACS,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA,IAI7B;AAEA,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,YAA+B;AAC3C,eAAW,aAAa,YAAY;AAElC,UAAI,CAAC,UAAU,UAAU;AACvB,cAAM,UACJ,OAAO,UAAU,OAAO,WACpB,UAAU,KACV,UAAU,GAAG,SAAS;AAC5B,kBAAU,WAAW,iBAAiB,OAAO;AAAA,MAC/C;AAGA,UAAI,CAAC,KAAK,WAAW,KAAK,CAAC,MAAM,EAAE,YAAY,UAAU,OAAO,GAAG;AACjE,aAAK,WAAW,KAAK,SAAS;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,KAA4B;AAE/C,UAAM,EAAE,SAAS,SAAS,IAAI,MAAM,OAAO,aAAa;AACxD,UAAM,EAAE,KAAK,IAAI,MAAM,OAAO,MAAM;AAEpC,UAAM,QAAQ,MAAM,QAAQ,GAAG;AAC/B,UAAM,iBAAiB,MAAM;AAAA,MAAO,CAAC,MACnC,EAAE,MAAM,uBAAuB;AAAA,IACjC;AAEA,eAAW,QAAQ,gBAAgB;AACjC,YAAM,WAAW,KAAK,KAAK,IAAI;AAC/B,YAAM,CAAC,SAAS,GAAG,SAAS,IAAI,KAC7B,QAAQ,kBAAkB,EAAE,EAC5B,MAAM,GAAG;AACZ,YAAM,OAAO,UAAU,KAAK,GAAG;AAE/B,UAAI,KAAK,SAAS,MAAM,GAAG;AAEzB,cAAM,UAAU,MAAM,SAAS,UAAU,OAAO;AAChD,cAAM,CAAC,IAAI,IAAI,IAAI,KAAK,kBAAkB,OAAO;AAEjD,aAAK,cAAc;AAAA,UACjB;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH,OAAO;AAEL,cAAMA,UAAS,MAAM,OAAO;AAC5B,aAAK,cAAc;AAAA,UACjB;AAAA,YACE;AAAA,YACA;AAAA,YACA,IAAIA,QAAO;AAAA,YACX,MAAMA,QAAO;AAAA,YACb,eAAeA,QAAO;AAAA,UACxB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,SAAmC;AAC3D,UAAM,UAAU,QAAQ,MAAM,wCAAwC;AACtE,UAAM,YAAY,QAAQ,MAAM,4BAA4B;AAE5D,UAAM,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,QAAQ,KAAK;AAChD,UAAM,OAAO,YAAY,CAAC,GAAG,KAAK,KAAK;AAEvC,WAAO,CAAC,IAAI,IAAI;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAmC;AACvC,UAAM,KAAK,WAAW;AAGtB,UAAM,SAAS,MAAM,KAAK,GAAG;AAAA,MAO3B;AAAA,cACQ,KAAK,SAAS;AAAA;AAAA,IAExB;AAEA,UAAM,UAA6B,OAAO,KAAK,IAAI,CAAC,SAAS;AAAA,MAC3D,SAAS,IAAI;AAAA,MACb,MAAM,IAAI;AAAA,MACV,WAAW,IAAI,KAAK,IAAI,UAAU;AAAA,MAClC,eAAe,IAAI;AAAA,MACnB,UAAU,IAAI,YAAY;AAAA,IAC5B,EAAE;AAEF,UAAM,kBAAkB,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAC7D,UAAM,mBAAmB,eAAe,KAAK,UAAU;AAEvD,UAAM,UAAU,iBAAiB;AAAA,MAC/B,CAAC,MAAM,CAAC,gBAAgB,IAAI,EAAE,OAAO;AAAA,IACvC;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,gBACE,QAAQ,SAAS,IAAI,QAAQ,QAAQ,SAAS,CAAC,EAAG,UAAU;AAAA,MAC9D,eACE,iBAAiB,SAAS,IACtB,iBAAiB,iBAAiB,SAAS,CAAC,EAAG,UAC/C;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,GACJ,UAA6C,CAAC,GAClB;AAC5B,UAAM,EAAE,SAAS,OAAO,GAAG,IAAI;AAC/B,UAAM,UAA6B,CAAC;AAEpC,QAAI,CAAC,QAAQ;AACX,YAAM,WAAW,MAAM,KAAK,KAAK;AACjC,UAAI,CAAC,UAAU;AACb,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,OAAO;AACjC,UAAI,UAAU,OAAO;AAGrB,UAAI,IAAI;AACN,cAAM,cAAc,QAAQ,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE;AAC7D,YAAI,gBAAgB,IAAI;AACtB,gBAAM,IAAI;AAAA,YACR,kBAAkB,EAAE;AAAA,UACtB;AAAA,QACF;AACA,kBAAU,QAAQ,MAAM,GAAG,cAAc,CAAC;AAAA,MAC5C;AAEA,iBAAW,aAAa,SAAS;AAC/B,cAAM,SAAS,MAAM,KAAK,aAAa,WAAW,MAAM,MAAM;AAC9D,gBAAQ,KAAK,MAAM;AAEnB,YAAI,CAAC,OAAO,SAAS;AACnB;AAAA,QACF;AAAA,MACF;AAAA,IACF,UAAE;AACA,UAAI,CAAC,QAAQ;AACX,cAAM,KAAK,OAAO;AAAA,MACpB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KACJ,UAAgD,CAAC,GACrB;AAC5B,UAAM,EAAE,SAAS,OAAO,QAAQ,EAAE,IAAI;AACtC,UAAM,UAA6B,CAAC;AAEpC,QAAI,CAAC,QAAQ;AACX,YAAM,WAAW,MAAM,KAAK,KAAK;AACjC,UAAI,CAAC,UAAU;AACb,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,OAAO;AAGjC,YAAM,aAAa,OAAO,QAAQ,MAAM,CAAC,KAAK,EAAE,QAAQ;AAExD,iBAAW,UAAU,YAAY;AAC/B,cAAM,YAAY,KAAK,WAAW;AAAA,UAChC,CAAC,MAAM,EAAE,YAAY,OAAO;AAAA,QAC9B;AACA,YAAI,CAAC,WAAW;AACd,gBAAM,IAAI;AAAA,YACR,aAAa,OAAO,OAAO;AAAA,UAC7B;AAAA,QACF;AAEA,cAAM,SAAS,MAAM,KAAK,aAAa,WAAW,QAAQ,MAAM;AAChE,gBAAQ,KAAK,MAAM;AAEnB,YAAI,CAAC,OAAO,SAAS;AACnB;AAAA,QACF;AAAA,MACF;AAAA,IACF,UAAE;AACA,UAAI,CAAC,QAAQ;AACX,cAAM,KAAK,OAAO;AAAA,MACpB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,UAAgC,CAAC,GAA+B;AAC1E,UAAM,SAAS,MAAM,KAAK,OAAO;AACjC,UAAM,cAAc,MAAM,KAAK,KAAK;AAAA,MAClC,QAAQ,QAAQ;AAAA,MAChB,OAAO,OAAO,QAAQ;AAAA,IACxB,CAAC;AAGD,QAAI,YAAY,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG;AACvC,YAAM,YAAY,MAAM,KAAK,GAAG,EAAE,QAAQ,QAAQ,OAAO,CAAC;AAC1D,aAAO,CAAC,GAAG,aAAa,GAAG,SAAS;AAAA,IACtC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KACJ,SACA,UAAgC,CAAC,GACL;AAC5B,UAAM,SAAS,MAAM,KAAK,OAAO;AACjC,UAAM,iBAAiB,OAAO;AAC9B,UAAM,UAA6B,CAAC;AAGpC,QAAI,mBAAmB,SAAS;AAC9B,aAAO;AAAA,IACT;AAGA,UAAM,OAAO,CAAC,kBAAkB,UAAU;AAE1C,QAAI,MAAM;AACR,aAAO,KAAK,GAAG,EAAE,GAAG,SAAS,IAAI,QAAQ,CAAC;AAAA,IAC5C,OAAO;AAEL,YAAM,eAAe,OAAO,QAAQ;AAAA,QAClC,CAAC,MAAM,EAAE,YAAY;AAAA,MACvB;AACA,YAAM,cAAc,OAAO,QAAQ;AAAA,QACjC,CAAC,MAAM,EAAE,YAAY;AAAA,MACvB;AAEA,UAAI,gBAAgB,IAAI;AACtB,cAAM,IAAI;AAAA,UACR,kBAAkB,OAAO;AAAA,QAC3B;AAAA,MACF;AAEA,YAAM,QAAQ,eAAe;AAC7B,aAAO,KAAK,KAAK,EAAE,GAAG,SAAS,MAAM,CAAC;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,aACZ,WACA,WACA,QAC0B;AAC1B,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,SAAS,cAAc,OAAO,UAAU,KAAK,UAAU;AAE7D,QAAI;AACF,UAAI,QAAQ;AAEV,eAAO;AAAA,UACL;AAAA,UACA,SAAS;AAAA,UACT,eAAe;AAAA,UACf,QAAQ;AAAA,QACV;AAAA,MACF;AAEA,YAAM,gBAAgB,UAAU,kBAAkB;AAClD,YAAM,YAAY,OAAO,OAA2B;AAClD,YAAI,OAAO,WAAW,UAAU;AAC9B,gBAAM,SAAS,MAAM,GAAG,IAAI,MAAM;AAClC,cAAI,OAAO,OAAO;AAChB,kBAAM,OAAO;AAAA,UACf;AAAA,QACF,OAAO;AACL,gBAAM,OAAO,EAAE;AAAA,QACjB;AAAA,MACF;AAEA,UAAI,eAAe;AACjB,cAAM,KAAK,GAAG,YAAY,OAAO,OAAO;AACtC,gBAAM,UAAU,EAAE;AAAA,QACpB,CAAC;AAAA,MACH,OAAO;AACL,cAAM,UAAU,KAAK,EAAE;AAAA,MACzB;AAEA,YAAM,gBAAgB,KAAK,IAAI,IAAI;AAGnC,UAAI,cAAc,MAAM;AACtB,cAAM,KAAK,GAAG;AAAA,UACZ,eAAe,KAAK,SAAS;AAAA;AAAA,UAE7B;AAAA,YACE,UAAU;AAAA,YACV,UAAU;AAAA,YACV;AAAA,YACA,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF,OAAO;AACL,cAAM,KAAK,GAAG,IAAI,eAAe,KAAK,SAAS,uBAAuB;AAAA,UACpE,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,QACL;AAAA,QACA,SAAS;AAAA,QACT;AAAA,QACA,QAAQ;AAAA,MACV;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL;AAAA,QACA,SAAS;AAAA,QACT,eAAe,KAAK,IAAI,IAAI;AAAA,QAC5B,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,QAC/D,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,MAA+B;AAC1C,UAAM,EAAE,WAAW,MAAM,IAAI,MAAM,OAAO,aAAa;AACvD,UAAM,EAAE,KAAK,IAAI,MAAM,OAAO,MAAM;AAEpC,QAAI,CAAC,KAAK,OAAO,eAAe;AAC9B,YAAM,IAAI,MAAM,uDAAuD;AAAA,IACzE;AAGA,UAAM,MAAM,KAAK,OAAO,eAAe,EAAE,WAAW,KAAK,CAAC;AAG1D,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,UAAU;AAAA,MACd,IAAI,YAAY;AAAA,MAChB,OAAO,IAAI,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,MAC1C,OAAO,IAAI,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,MACrC,OAAO,IAAI,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,MACtC,OAAO,IAAI,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,MACxC,OAAO,IAAI,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,IAC1C,EAAE,KAAK,EAAE;AAET,UAAM,WAAW,KAAK,QAAQ,kBAAkB,GAAG,EAAE,YAAY;AACjE,UAAM,WAAW,GAAG,OAAO,IAAI,QAAQ;AACvC,UAAM,WAAW,KAAK,KAAK,OAAO,eAAe,QAAQ;AAEzD,UAAM,WAAW,iBAAiB,IAAI;AAAA,cAC5B,OAAO;AAAA,cACP,IAAI,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAW3B,UAAM,UAAU,UAAU,UAAU,OAAO;AAE3C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAA0D;AAC9D,UAAM,SAAmB,CAAC;AAC1B,UAAM,SAAS,MAAM,KAAK,OAAO;AAEjC,QAAI,CAAC,KAAK,OAAO,mBAAmB;AAClC,aAAO,EAAE,OAAO,MAAM,OAAO;AAAA,IAC/B;AAEA,eAAW,WAAW,OAAO,SAAS;AACpC,YAAM,YAAY,KAAK,WAAW;AAAA,QAChC,CAAC,MAAM,EAAE,YAAY,QAAQ;AAAA,MAC/B;AAEA,UAAI,CAAC,WAAW;AACd,eAAO;AAAA,UACL,aAAa,QAAQ,OAAO,KAAK,QAAQ,IAAI;AAAA,QAC/C;AACA;AAAA,MACF;AAEA,UAAI,QAAQ,YAAY,UAAU,aAAa,QAAQ,UAAU;AAC/D,eAAO;AAAA,UACL,aAAa,QAAQ,OAAO,KAAK,QAAQ,IAAI;AAAA,QAC/C;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,OAAO,OAAO,WAAW;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AACF;;;AC9kBO,SAAS,aAAa,WAMf;AACZ,SAAO;AAAA,IACL,SAAS,UAAU;AAAA,IACnB,MAAM,UAAU;AAAA,IAChB,IAAI,UAAU;AAAA,IACd,MAAM,UAAU;AAAA,IAChB,eAAe,UAAU;AAAA,EAC3B;AACF;AAqBO,SAAS,gBAAgB,WAMlB;AACZ,SAAO;AAAA,IACL,SAAS,UAAU;AAAA,IACnB,MAAM,UAAU;AAAA,IAChB,IAAI,UAAU;AAAA,IACd,MAAM,UAAU;AAAA,IAChB,eAAe,UAAU;AAAA,EAC3B;AACF;AAyBO,SAAS,gBAQd,WAAyB;AACzB,SAAO;AACT;;;ACnFO,IAAM,4BAAuC;AAAA,EAClD,SAAS;AAAA,EACT,MAAM;AAAA,EACN,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBJ,MAAM;AACR;AAKO,IAAM,iCAA4C;AAAA,EACvD,SAAS;AAAA,EACT,MAAM;AAAA,EACN,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBJ,MAAM;AACR;AAKO,IAAM,6BAAwC;AAAA,EACnD,SAAS;AAAA,EACT,MAAM;AAAA,EACN,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYJ,MAAM;AACR;AAKO,IAAM,qBAAgC;AAAA,EAC3C,SAAS;AAAA,EACT,MAAM;AAAA,EACN,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBJ,MAAM;AACR;AAKO,IAAM,2BAAsC;AAAA,EACjD,SAAS;AAAA,EACT,MAAM;AAAA,EACN,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBJ,MAAM;AACR;AAKO,IAAM,+BAA0C;AAAA,EACrD,SAAS;AAAA,EACT,MAAM;AAAA,EACN,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBJ,MAAM;AACR;AAKO,IAAM,yBAAoC;AAAA,EAC/C,SAAS;AAAA,EACT,MAAM;AAAA,EACN,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWJ,MAAM;AACR;AAKO,IAAM,yBAAoC;AAAA,EAC/C,SAAS;AAAA,EACT,MAAM;AAAA,EACN,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBJ,MAAM;AACR;AAKO,IAAM,uBAAoC;AAAA,EAC/C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,SAAS,wBAAwB,UAGxB;AACd,QAAM,aAA0B,CAAC;AAEjC,MAAI,SAAS,KAAK;AAChB,eAAW;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,SAAS,SAAS;AACpB,eAAW;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;","names":["module"]}
@@ -208,7 +208,9 @@ var Migrator = class {
208
208
  if (!dryRun) {
209
209
  const acquired = await this.lock();
210
210
  if (!acquired) {
211
- throw new Error("Could not acquire migration lock. Another migration may be in progress.");
211
+ throw new Error(
212
+ "Could not acquire migration lock. Another migration may be in progress."
213
+ );
212
214
  }
213
215
  }
214
216
  try {
@@ -217,7 +219,9 @@ var Migrator = class {
217
219
  if (to) {
218
220
  const targetIndex = pending.findIndex((m) => m.version === to);
219
221
  if (targetIndex === -1) {
220
- throw new Error(`Target version ${to} not found in pending migrations`);
222
+ throw new Error(
223
+ `Target version ${to} not found in pending migrations`
224
+ );
221
225
  }
222
226
  pending = pending.slice(0, targetIndex + 1);
223
227
  }
@@ -244,14 +248,18 @@ var Migrator = class {
244
248
  if (!dryRun) {
245
249
  const acquired = await this.lock();
246
250
  if (!acquired) {
247
- throw new Error("Could not acquire migration lock. Another migration may be in progress.");
251
+ throw new Error(
252
+ "Could not acquire migration lock. Another migration may be in progress."
253
+ );
248
254
  }
249
255
  }
250
256
  try {
251
257
  const status = await this.status();
252
258
  const toRollback = status.applied.slice(-steps).reverse();
253
259
  for (const record of toRollback) {
254
- const migration = this.migrations.find((m) => m.version === record.version);
260
+ const migration = this.migrations.find(
261
+ (m) => m.version === record.version
262
+ );
255
263
  if (!migration) {
256
264
  throw new Error(
257
265
  `Migration ${record.version} was applied but is not registered. Cannot rollback.`
@@ -299,10 +307,16 @@ var Migrator = class {
299
307
  if (isUp) {
300
308
  return this.up({ ...options, to: version });
301
309
  } else {
302
- const currentIndex = status.applied.findIndex((m) => m.version === currentVersion);
303
- const targetIndex = status.applied.findIndex((m) => m.version === version);
310
+ const currentIndex = status.applied.findIndex(
311
+ (m) => m.version === currentVersion
312
+ );
313
+ const targetIndex = status.applied.findIndex(
314
+ (m) => m.version === version
315
+ );
304
316
  if (targetIndex === -1) {
305
- throw new Error(`Target version ${version} not found in applied migrations`);
317
+ throw new Error(
318
+ `Target version ${version} not found in applied migrations`
319
+ );
306
320
  }
307
321
  const steps = currentIndex - targetIndex;
308
322
  return this.down({ ...options, steps });
@@ -346,13 +360,17 @@ var Migrator = class {
346
360
  await this.db.raw(
347
361
  `INSERT INTO ${this.tableName} (version, name, execution_time, checksum)
348
362
  VALUES ($1, $2, $3, $4)`,
349
- [migration.version, migration.name, executionTime, migration.checksum]
363
+ [
364
+ migration.version,
365
+ migration.name,
366
+ executionTime,
367
+ migration.checksum
368
+ ]
350
369
  );
351
370
  } else {
352
- await this.db.raw(
353
- `DELETE FROM ${this.tableName} WHERE version = $1`,
354
- [migration.version]
355
- );
371
+ await this.db.raw(`DELETE FROM ${this.tableName} WHERE version = $1`, [
372
+ migration.version
373
+ ]);
356
374
  }
357
375
  return {
358
376
  migration,
@@ -417,7 +435,9 @@ var Migrator = class {
417
435
  return { valid: true, errors };
418
436
  }
419
437
  for (const applied of status.applied) {
420
- const migration = this.migrations.find((m) => m.version === applied.version);
438
+ const migration = this.migrations.find(
439
+ (m) => m.version === applied.version
440
+ );
421
441
  if (!migration) {
422
442
  errors.push(
423
443
  `Migration ${applied.version} (${applied.name}) was applied but is not registered`