{"version":3,"sources":["../src/migrations.ts"],"names":["createHash"],"mappings":"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","file":"migrations.cjs","sourcesContent":["/**\n * Database migration utilities.\n *\n * @remarks\n * Provides core utilities for migration management including checksum calculation,\n * sorting, filtering, and validation. Also includes optional helpers for adapters\n * to use for common migration operations.\n *\n * @packageDocumentation\n */\n\nimport { createHash } from \"crypto\";\n\nimport type { DrizzleAdapter } from \"./adapter\";\nimport type {\n  Migration,\n  MigrationRecord,\n  MigrationStatus,\n  MigrationOptions,\n} from \"./types/migration\";\n\n// ============================================================\n// Core Utilities\n// ============================================================\n\n/**\n * Calculate SHA-256 checksum for a migration.\n *\n * @remarks\n * Creates a checksum of the entire migration object including id, name, timestamp,\n * and the string representation of up/down functions. This allows detection of\n * any changes to the migration after it has been applied.\n *\n * @param migration - Migration to calculate checksum for\n * @returns Hexadecimal SHA-256 hash\n *\n * @example\n * ```typescript\n * const migration: Migration = {\n *   id: \"20250104_001_create_users\",\n *   name: \"Create users table\",\n *   timestamp: 1704326400000,\n *   up: \"CREATE TABLE users (id UUID PRIMARY KEY);\",\n * };\n *\n * const checksum = calculateChecksum(migration);\n * // Returns: \"a3f5b8c9d2e1f0...\"\n * ```\n *\n * @public\n */\nexport function calculateChecksum(migration: Migration): string {\n  // Serialize migration to a consistent string format\n  const content = JSON.stringify({\n    id: migration.id,\n    name: migration.name,\n    timestamp: migration.timestamp,\n    up:\n      typeof migration.up === \"string\" ? migration.up : migration.up.toString(),\n    down:\n      typeof migration.down === \"string\"\n        ? migration.down\n        : migration.down?.toString() || null,\n  });\n\n  // Create SHA-256 hash\n  return createHash(\"sha256\").update(content, \"utf8\").digest(\"hex\");\n}\n\n/**\n * Sort migrations by timestamp in ascending order.\n *\n * @remarks\n * Provides deterministic ordering of migrations. If timestamps are equal,\n * falls back to sorting by migration ID alphabetically.\n *\n * @param migrations - Array of migrations to sort\n * @returns New sorted array (original array is not modified)\n *\n * @example\n * ```typescript\n * const migrations = [\n *   { id: \"003\", timestamp: 1704412800000, ... },\n *   { id: \"001\", timestamp: 1704326400000, ... },\n *   { id: \"002\", timestamp: 1704326400000, ... },\n * ];\n *\n * const sorted = sortMigrations(migrations);\n * // Returns: [001, 002, 003] (001 and 002 same timestamp, sorted by id)\n * ```\n *\n * @public\n */\nexport function sortMigrations(migrations: Migration[]): Migration[] {\n  return [...migrations].sort((a, b) => {\n    // Primary sort: timestamp ascending\n    if (a.timestamp !== b.timestamp) {\n      return a.timestamp - b.timestamp;\n    }\n    // Secondary sort: id alphabetically (for deterministic ordering)\n    return a.id.localeCompare(b.id);\n  });\n}\n\n/**\n * Filter migrations to get only pending (unapplied) migrations.\n *\n * @remarks\n * Returns migrations that have not been applied to the database yet.\n * A migration is considered pending if its ID is not present in the\n * applied migration records.\n *\n * @param migrations - All available migrations\n * @param applied - Records of applied migrations from database\n * @returns Array of pending migrations\n *\n * @example\n * ```typescript\n * const allMigrations = [\n *   { id: \"001_create_users\", ... },\n *   { id: \"002_create_posts\", ... },\n *   { id: \"003_create_comments\", ... },\n * ];\n *\n * const appliedRecords = [\n *   { id: \"001_create_users\", appliedAt: new Date(), ... },\n * ];\n *\n * const pending = filterPending(allMigrations, appliedRecords);\n * // Returns: [002_create_posts, 003_create_comments]\n * ```\n *\n * @public\n */\nexport function filterPending(\n  migrations: Migration[],\n  applied: MigrationRecord[]\n): Migration[] {\n  const appliedIds = new Set(applied.map(record => record.id));\n  return migrations.filter(migration => !appliedIds.has(migration.id));\n}\n\n/**\n * Filter migration records to get only those that match given migrations.\n *\n * @remarks\n * Returns applied migration records that correspond to the given migrations.\n * Useful for getting the subset of applied records relevant to a specific\n * set of migrations.\n *\n * @param migrations - Migrations to match\n * @param applied - All applied migration records from database\n * @returns Array of matching applied records\n *\n * @example\n * ```typescript\n * const migrations = [\n *   { id: \"001_create_users\", ... },\n *   { id: \"002_create_posts\", ... },\n * ];\n *\n * const allApplied = [\n *   { id: \"001_create_users\", appliedAt: new Date(), ... },\n *   { id: \"002_create_posts\", appliedAt: new Date(), ... },\n *   { id: \"003_create_comments\", appliedAt: new Date(), ... },\n * ];\n *\n * const relevant = filterApplied(migrations, allApplied);\n * // Returns: [001_create_users, 002_create_posts]\n * ```\n *\n * @public\n */\nexport function filterApplied(\n  migrations: Migration[],\n  applied: MigrationRecord[]\n): MigrationRecord[] {\n  const migrationIds = new Set(migrations.map(migration => migration.id));\n  return applied.filter(record => migrationIds.has(record.id));\n}\n\n/**\n * Validate that a migration's checksum matches its applied record.\n *\n * @remarks\n * Compares the calculated checksum of a migration against the stored checksum\n * in its migration record. Returns false if checksums don't match or if the\n * record has no checksum.\n *\n * @param migration - Migration to validate\n * @param record - Applied migration record with stored checksum\n * @returns true if checksums match, false otherwise\n *\n * @example\n * ```typescript\n * const migration: Migration = { id: \"001\", ... };\n * const record: MigrationRecord = {\n *   id: \"001\",\n *   checksum: \"a3f5b8c9...\",\n *   ...\n * };\n *\n * const isValid = validateChecksum(migration, record);\n * // Returns: true if checksums match, false if modified\n * ```\n *\n * @public\n */\nexport function validateChecksum(\n  migration: Migration,\n  record: MigrationRecord\n): boolean {\n  if (!record.checksum) {\n    // No checksum stored, cannot validate\n    return false;\n  }\n\n  const currentChecksum = calculateChecksum(migration);\n  return currentChecksum === record.checksum;\n}\n\n/**\n * Detect migrations that have been modified after being applied.\n *\n * @remarks\n * Compares checksums of migrations against their applied records to detect\n * any modifications. Returns records for migrations that have been changed\n * since they were applied to the database.\n *\n * This is critical for detecting potentially dangerous situations where a\n * migration that has already run has been modified.\n *\n * @param migrations - Current migrations\n * @param applied - Applied migration records with checksums\n * @returns Array of records for modified migrations\n *\n * @example\n * ```typescript\n * const migrations = [{ id: \"001\", up: \"CREATE TABLE users_v2 ...\" }];\n * const applied = [{ id: \"001\", checksum: \"original_hash\", ... }];\n *\n * const modified = detectModified(migrations, applied);\n * // Returns: [{ id: \"001\", ... }] if migration was changed\n * ```\n *\n * @public\n */\nexport function detectModified(\n  migrations: Migration[],\n  applied: MigrationRecord[]\n): MigrationRecord[] {\n  const migrationMap = new Map(migrations.map(m => [m.id, m]));\n  const modified: MigrationRecord[] = [];\n\n  for (const record of applied) {\n    const migration = migrationMap.get(record.id);\n    if (migration && !validateChecksum(migration, record)) {\n      modified.push(record);\n    }\n  }\n\n  return modified;\n}\n\n/**\n * Get comprehensive migration status.\n *\n * @remarks\n * Analyzes migrations and applied records to produce a complete status report\n * including current migration, applied/pending counts, and full lists.\n *\n * @param migrations - All available migrations\n * @param applied - Applied migration records from database\n * @returns Complete migration status information\n *\n * @example\n * ```typescript\n * const status = getMigrationStatus(allMigrations, appliedRecords);\n * console.log(`Current: ${status.current}`);\n * console.log(`Applied: ${status.appliedCount}, Pending: ${status.pendingCount}`);\n * ```\n *\n * @public\n */\nexport function getMigrationStatus(\n  migrations: Migration[],\n  applied: MigrationRecord[]\n): MigrationStatus {\n  const sortedMigrations = sortMigrations(migrations);\n  const sortedApplied = [...applied].sort(\n    (a, b) => b.appliedAt.getTime() - a.appliedAt.getTime()\n  );\n\n  const pending = filterPending(sortedMigrations, applied);\n  const current = sortedApplied.length > 0 ? sortedApplied[0].id : null;\n\n  return {\n    current,\n    appliedCount: applied.length,\n    pendingCount: pending.length,\n    applied,\n    pending,\n  };\n}\n\n// ============================================================\n// Migration Validation\n// ============================================================\n\n/**\n * Validation result for migrations.\n *\n * @public\n */\nexport interface MigrationValidationResult {\n  /** Whether all validations passed */\n  valid: boolean;\n\n  /** List of validation errors */\n  errors: string[];\n\n  /** List of validation warnings */\n  warnings: string[];\n\n  /** Migrations that have been modified */\n  modified: MigrationRecord[];\n\n  /** Duplicate migration IDs found */\n  duplicates: string[];\n}\n\n/**\n * Validate migrations for common issues.\n *\n * @remarks\n * Performs comprehensive validation including:\n * - Duplicate migration IDs\n * - Modified applied migrations (checksum mismatch)\n * - Missing required fields\n * - Invalid timestamps\n *\n * @param migrations - Migrations to validate\n * @param applied - Applied migration records (for checksum validation)\n * @param options - Migration options (for strictness configuration)\n * @returns Validation result with errors and warnings\n *\n * @example\n * ```typescript\n * const result = validateMigrations(migrations, applied, {\n *   strictChecksums: true\n * });\n *\n * if (!result.valid) {\n *   console.error(\"Validation errors:\", result.errors);\n *   throw new Error(\"Migration validation failed\");\n * }\n * ```\n *\n * @public\n */\nexport function validateMigrations(\n  migrations: Migration[],\n  applied: MigrationRecord[],\n  options?: MigrationOptions\n): MigrationValidationResult {\n  const errors: string[] = [];\n  const warnings: string[] = [];\n  const duplicates: string[] = [];\n\n  // Check for duplicate IDs\n  const idCounts = new Map<string, number>();\n  for (const migration of migrations) {\n    const count = (idCounts.get(migration.id) || 0) + 1;\n    idCounts.set(migration.id, count);\n    if (count > 1) {\n      duplicates.push(migration.id);\n    }\n  }\n\n  if (duplicates.length > 0) {\n    errors.push(`Duplicate migration IDs found: ${duplicates.join(\", \")}`);\n  }\n\n  // Validate required fields\n  for (const migration of migrations) {\n    if (!migration.id) {\n      errors.push(\"Migration missing required field: id\");\n    }\n    if (!migration.name) {\n      errors.push(`Migration ${migration.id} missing required field: name`);\n    }\n    if (!migration.timestamp || typeof migration.timestamp !== \"number\") {\n      errors.push(`Migration ${migration.id} missing or invalid timestamp`);\n    }\n    if (!migration.up) {\n      errors.push(`Migration ${migration.id} missing required field: up`);\n    }\n  }\n\n  // Check for modified migrations\n  const modified = detectModified(migrations, applied);\n\n  if (modified.length > 0) {\n    const modifiedIds = modified.map(r => r.id).join(\", \");\n    const message = `Applied migrations have been modified: ${modifiedIds}`;\n\n    // Use strictChecksums option if available, default to true (strict)\n    const strictChecksums = options?.strictChecksums ?? true;\n\n    if (strictChecksums) {\n      errors.push(message);\n    } else {\n      warnings.push(message);\n    }\n  }\n\n  return {\n    valid: errors.length === 0,\n    errors,\n    warnings,\n    modified,\n    duplicates,\n  };\n}\n\n// ============================================================\n// Migration Helpers (for adapters)\n// ============================================================\n\n/**\n * Helper functions for managing migrations in database adapters.\n *\n * @remarks\n * These helpers reduce boilerplate code in dialect-specific adapters by\n * providing common operations like creating migration tables, recording\n * migrations, and querying migration status.\n *\n * Adapters can use these helpers or implement their own logic.\n *\n * @public\n */\nexport interface MigrationHelpers {\n  /**\n   * Create the migrations tracking table if it doesn't exist.\n   *\n   * @remarks\n   * Creates a table named `nextly_migrations` with columns:\n   * - id (string, primary key)\n   * - name (string)\n   * - applied_at (timestamp)\n   * - checksum (string, optional)\n   *\n   * Uses CREATE TABLE IF NOT EXISTS for safety.\n   *\n   * @param adapter - Database adapter to use\n   * @returns Promise that resolves when table is created\n   */\n  createMigrationsTable(adapter: DrizzleAdapter): Promise<void>;\n\n  /**\n   * Get all applied migration records from the database.\n   *\n   * @remarks\n   * Queries the `nextly_migrations` table and returns all records\n   * sorted by applied_at descending (most recent first).\n   *\n   * @param adapter - Database adapter to use\n   * @returns Promise with array of applied migration records\n   */\n  getAppliedMigrations(adapter: DrizzleAdapter): Promise<MigrationRecord[]>;\n\n  /**\n   * Record a migration as applied in the database.\n   *\n   * @remarks\n   * Inserts a new record into the `nextly_migrations` table with:\n   * - Migration ID, name\n   * - Current timestamp for applied_at\n   * - Calculated checksum\n   *\n   * Should be called within a transaction during migration execution.\n   *\n   * @param adapter - Database adapter to use\n   * @param migration - Migration that was applied\n   * @returns Promise that resolves when record is inserted\n   */\n  recordMigration(adapter: DrizzleAdapter, migration: Migration): Promise<void>;\n\n  /**\n   * Remove a migration record from the database.\n   *\n   * @remarks\n   * Deletes a record from the `nextly_migrations` table.\n   * Used during migration rollback operations.\n   *\n   * Should be called within a transaction during rollback.\n   *\n   * @param adapter - Database adapter to use\n   * @param migrationId - ID of the migration to remove\n   * @returns Promise that resolves when record is deleted\n   */\n  removeMigrationRecord(\n    adapter: DrizzleAdapter,\n    migrationId: string\n  ): Promise<void>;\n\n  /**\n   * Check if migrations table exists.\n   *\n   * @remarks\n   * Queries database metadata to check if the `nextly_migrations` table exists.\n   * Useful for determining if initialization is needed.\n   *\n   * @param adapter - Database adapter to use\n   * @returns Promise with boolean indicating if table exists\n   */\n  migrationsTableExists(adapter: DrizzleAdapter): Promise<boolean>;\n}\n\n/**\n * Implementation of migration helpers.\n *\n * @remarks\n * Provides default implementations using the adapter's query methods.\n * These work across all dialects but adapters can optimize for their\n * specific database if needed.\n *\n * @public\n */\nexport const migrationHelpers: MigrationHelpers = {\n  async createMigrationsTable(adapter: DrizzleAdapter): Promise<void> {\n    const caps = adapter.getCapabilities();\n    const dialect = caps.dialect;\n\n    // Build CREATE TABLE statement with dialect-specific syntax\n    let sql = \"\";\n\n    if (dialect === \"postgresql\") {\n      sql = `\n        CREATE TABLE IF NOT EXISTS nextly_migrations (\n          id VARCHAR(255) PRIMARY KEY,\n          name VARCHAR(255) NOT NULL,\n          applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n          checksum VARCHAR(64)\n        )\n      `;\n    } else if (dialect === \"mysql\") {\n      sql = `\n        CREATE TABLE IF NOT EXISTS nextly_migrations (\n          id VARCHAR(255) PRIMARY KEY,\n          name VARCHAR(255) NOT NULL,\n          applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n          checksum VARCHAR(64)\n        )\n      `;\n    } else if (dialect === \"sqlite\") {\n      sql = `\n        CREATE TABLE IF NOT EXISTS nextly_migrations (\n          id TEXT PRIMARY KEY,\n          name TEXT NOT NULL,\n          applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,\n          checksum TEXT\n        )\n      `;\n    } else {\n      throw new Error(`Unsupported dialect: ${String(dialect)}`);\n    }\n\n    await adapter.executeQuery(sql);\n  },\n\n  async getAppliedMigrations(\n    adapter: DrizzleAdapter\n  ): Promise<MigrationRecord[]> {\n    const results = await adapter.select<{\n      id: string;\n      name: string;\n      applied_at: Date;\n      checksum?: string;\n    }>(\"nextly_migrations\", {\n      orderBy: [{ column: \"applied_at\", direction: \"desc\" }],\n    });\n\n    return results.map(row => ({\n      id: row.id,\n      name: row.name,\n      appliedAt: new Date(row.applied_at),\n      checksum: row.checksum,\n    }));\n  },\n\n  async recordMigration(\n    adapter: DrizzleAdapter,\n    migration: Migration\n  ): Promise<void> {\n    const checksum = calculateChecksum(migration);\n\n    await adapter.insert(\"nextly_migrations\", {\n      id: migration.id,\n      name: migration.name,\n      applied_at: new Date(),\n      checksum,\n    });\n  },\n\n  async removeMigrationRecord(\n    adapter: DrizzleAdapter,\n    migrationId: string\n  ): Promise<void> {\n    await adapter.delete(\"nextly_migrations\", {\n      and: [{ column: \"id\", op: \"=\", value: migrationId }],\n    });\n  },\n\n  async migrationsTableExists(adapter: DrizzleAdapter): Promise<boolean> {\n    try {\n      // Try to query the table - if it doesn't exist, this will throw\n      await adapter.select(\"nextly_migrations\", { limit: 1 });\n      return true;\n    } catch {\n      return false;\n    }\n  },\n};\n\n// ============================================================\n// Type Exports\n// ============================================================\n\n// Re-export migration types for convenience\nexport type {\n  Migration,\n  MigrationRecord,\n  MigrationResult,\n  MigrationStatus,\n  MigrationOptions,\n} from \"./types/migration\";\n"]}