Migrations API reference
Current emitted signatures and options for @db3.ai/app/db/migrations.
On this page
Source-backed MarkdownImports and examples
Import supported APIs from @db3.ai/app/db/migrations. These signatures come from the staged package used by consumers. Relative filenames in declarations describe type dependencies; they are not extra supported deep imports.
Use the guide for setup, executable examples, failure handling and ownership. A signature is not proof that every deployment or provider has been exercised.
Migration manager
ts
import type { DatabaseCheckResult, DatabaseMigrationManagerOptions, DatabaseMigrationStatus, DatabaseSyncResult, MakeMigrationOptions, MakeMigrationResult, MigrateOptions, MigrateResult } from './contracts/index.js';
/**
* Reusable application-configured model migration service.
*
* CLI commands, development HTTP actions, and deployment scripts should call
* this service rather than duplicating model collection or Knex execution.
*/
export declare class DatabaseMigrationManager {
#private;
/**
* Creates a migration manager with app-owned models, paths, and ledger name.
*
* @param options - Database connection, model registry, and absolute source paths.
*/
constructor(options: DatabaseMigrationManagerOptions);
/**
* Returns model, snapshot, live database, and Knex migration status without
* creating the Knex migration ledger.
*
* @returns Structured status suitable for CLI or development UI rendering.
*/
status(): Promise<DatabaseMigrationStatus>;
/**
* Checks the live model-owned database subset against current models.
*
* Extra columns and tables are ignored to preserve additive blue/green
* compatibility, while missing or incompatible requirements are reported.
*
* @returns Structured database compatibility result.
*/
check(): Promise<DatabaseCheckResult>;
/**
* Generates a frozen migration and advances the committed snapshot when
* current models contain only supported changes.
*
* @param options - Optional human-readable migration name.
* @returns Generation result including blocked changes or written file path.
*/
makeMigration(options?: MakeMigrationOptions): Promise<MakeMigrationResult>;
/**
* Applies pending committed migrations through Knex's ledger and lock.
*
* @param options - Optional matching-database baseline policy.
* @returns Applied migration names, batch, and optional baselined filenames.
*/
migrate(options?: MigrateOptions): Promise<MigrateResult>;
/**
* Runs the development convenience flow under one generation lock.
*
* A blocked model diff returns immediately without applying migrations. A
* successful flow always finishes with a live database compatibility check.
*
* @param options - Optional human-readable generated migration name.
* @returns Structured make, migrate, and check results.
*/
sync(options?: MakeMigrationOptions): Promise<DatabaseSyncResult>;
}
Options and workflow results
ts
import type { Knex } from 'knex';
import type { ActiveRecordClass } from '../../ActiveRecord.js';
import type { DatabaseDialect } from '../../dialects/index.js';
import type { SchemaMigrationPlan } from './SchemaChange.js';
/**
* Application-owned paths and runtime policy for database migration tooling.
*/
export interface DatabaseMigrationManagerOptions {
/** Knex connection used for migration execution and database inspection. */
db: Knex;
/** Complete set of ActiveRecord models owned by the application. */
models: readonly ActiveRecordClass[];
/** Dialect used to collect field schema metadata. MariaDB is supported first. */
dialect: DatabaseDialect;
/** Absolute directory containing permanent Knex migration files. */
migrationsDirectory: string;
/** Absolute path of the committed desired-schema snapshot. */
snapshotFile: string;
/** Knex migration ledger table. Its lock table follows Knex naming. */
migrationTableName?: string;
/** Optional database schema containing the Knex migration ledger. */
migrationSchemaName?: string;
/** Migration file extensions Knex may load. */
loadExtensions?: readonly string[];
/** Current application environment. Source generation is refused in production. */
environment?: string;
/** Absolute cross-process lock path used while generating source files. */
generationLockFile?: string;
/** Injectable clock used for deterministic migration filenames in tests. */
now?: () => Date;
}
/**
* Persisted and pending Knex migration names without mutating the ledger.
*/
export interface DatabaseMigrationState {
completed: string[];
pending: string[];
missingFiles: string[];
}
/**
* Combined model, snapshot, database, and Knex status for CLI or development UI.
*/
export interface DatabaseMigrationStatus {
snapshotExists: boolean;
modelsMatchSnapshot: boolean;
databaseMatchesModels: boolean;
generationPlan: SchemaMigrationPlan;
databasePlan: SchemaMigrationPlan;
migrations: DatabaseMigrationState;
}
/**
* Result returned after checking the live database against current models.
*/
export interface DatabaseCheckResult {
/** Whether the live model-owned schema satisfies current models. */
schemaMatches: boolean;
/** Whether current models have a corresponding committed snapshot. */
modelsMatchSnapshot: boolean;
/** Overall readiness including snapshot and Knex migration state. */
matches: boolean;
/** Differences between the live model-owned schema and current models. */
plan: SchemaMigrationPlan;
/** Differences between the committed snapshot and current models. */
snapshotPlan: SchemaMigrationPlan;
/** Completed, pending, and corrupt Knex migration history. */
migrations: DatabaseMigrationState;
}
/**
* Options accepted when generating one permanent migration file.
*/
export interface MakeMigrationOptions {
/** Human-readable migration name. A deterministic name is inferred when omitted. */
name?: string;
/**
* When true, generate drop DDL for blocked column/index/foreign-key/table
* removals after warning. Other blocked operations still refuse generation.
*/
allowDestructive?: boolean;
}
/**
* Result of comparing models with the committed snapshot and optionally writing
* a new migration.
*/
export interface MakeMigrationResult {
generated: boolean;
blocked: boolean;
file: string | null;
plan: SchemaMigrationPlan;
}
/**
* Options used when applying permanent Knex migrations.
*/
/**
* Optional controls for applying committed migrations.
*/
export interface MigrateOptions {
/**
* Adopt all pending migrations without DDL when an existing untracked
* database already matches the committed schema snapshot.
*/
baselineIfMatching?: boolean;
}
/**
* Result of applying pending Knex migrations.
*/
export interface MigrateResult {
applied: string[];
batch: number | null;
baselined: string[] | null;
}
/**
* Result of the development `make -> migrate -> check` convenience operation.
*/
export interface DatabaseSyncResult {
make: MakeMigrationResult;
migrate: MigrateResult | null;
check: DatabaseCheckResult | null;
}
Schema change plans
ts
import type { SchemaColumn, SchemaForeignKey, SchemaIndex, SchemaTable } from './SchemaSnapshot.js';
/**
* Schema operation that the first migration generator can apply safely.
*/
export type SafeSchemaChange = {
kind: 'create_table';
table: SchemaTable;
description: string;
} | {
kind: 'add_column';
tableName: string;
column: SchemaColumn;
description: string;
} | {
kind: 'add_index';
tableName: string;
index: SchemaIndex;
description: string;
} | {
kind: 'add_foreign_key';
tableName: string;
foreignKey: SchemaForeignKey;
description: string;
} | {
kind: 'alter_column';
tableName: string;
column: SchemaColumn;
alterType: boolean;
alterNullable: boolean;
alterComment: boolean;
/** Whether the generated alteration changes or removes the database default. */
alterDefault: boolean;
description: string;
} | {
kind: 'alter_table_comment';
tableName: string;
comment: string | null;
description: string;
} | {
kind: 'drop_column';
tableName: string;
columnName: string;
description: string;
} | {
kind: 'drop_index';
tableName: string;
indexName: string;
description: string;
} | {
kind: 'drop_foreign_key';
tableName: string;
foreignKeyName: string;
description: string;
} | {
kind: 'drop_table';
tableName: string;
description: string;
};
/**
* Potentially destructive or ambiguous operation requiring a reviewed manual
* migration before the snapshot can advance.
*/
export interface BlockedSchemaChange {
kind: 'blocked_change';
operation: 'add_required_column' | 'add_unique_column' | 'add_index_to_existing_columns' | 'add_foreign_key_to_existing_column' | 'remove_table' | 'remove_column' | 'remove_index' | 'remove_foreign_key' | 'alter_column_type' | 'tighten_column_nullability' | 'alter_column_primary' | 'alter_column_unique' | 'alter_index' | 'alter_foreign_key';
tableName: string;
columnName?: string;
objectName?: string;
description: string;
}
/**
* Pure result of comparing a previous snapshot with a desired snapshot.
*/
export interface SchemaMigrationPlan {
/** Stable hash of the previous schema snapshot. */
fromHash: string;
/** Stable hash of the desired schema snapshot. */
toHash: string;
/** Automatically renderable additive or widening changes. */
safeChanges: SafeSchemaChange[];
/** Changes that must stop automatic generation. */
blockedChanges: BlockedSchemaChange[];
}
Schema snapshots
ts
import type { DatabaseDialectName } from '../../dialects/index.js';
/**
* JSON-safe value that can be frozen into a schema snapshot and migration.
*/
export type SchemaValue = null | string | number | boolean | SchemaValue[] | {
[key: string]: SchemaValue;
};
/**
* Normalized database column owned by an ActiveRecord model.
*/
export interface SchemaColumn {
/** Physical database column name. */
name: string;
/** Dialect-specific SQL column type. */
type: string;
/** Whether the database column accepts null values. */
nullable: boolean;
/** Whether the database column is the table primary key. */
primary: boolean;
/** Whether the database column has a single-column unique constraint. */
unique: boolean;
/** Static database default, when the model declares one. */
default?: SchemaValue;
/** Normalized database-native column comment. */
comment: string | null;
}
/**
* One ordered column in a normalized database index.
*/
export interface SchemaIndexColumn {
/** Physical database column name. */
name: string;
/** Optional explicit index ordering. */
order?: 'asc' | 'desc';
}
/**
* Named database index owned by an ActiveRecord model.
*/
export interface SchemaIndex {
/** Stable database index name. */
name: string;
/** Ordered columns included in the index. */
columns: SchemaIndexColumn[];
/** Whether values must be unique across the index columns. */
unique: boolean;
/** Database index implementation. */
type: 'normal' | 'vector';
}
/**
* Named foreign-key constraint owned by an ActiveRecord model.
*/
export interface SchemaForeignKey {
/** Stable database constraint name. */
name: string;
/** Local physical database column. */
column: string;
/** Referenced physical database table. */
referencesTable: string;
/** Referenced physical database column. */
referencesColumn: string;
/** Optional action applied when a referenced row is deleted. */
onDelete?: 'CASCADE' | 'RESTRICT' | 'SET NULL' | 'NO ACTION';
/** Optional action applied when a referenced key changes. */
onUpdate?: 'CASCADE' | 'RESTRICT' | 'SET NULL' | 'NO ACTION';
}
/**
* Normalized database table owned by one ActiveRecord model.
*/
export interface SchemaTable {
/** Physical database table name. */
name: string;
/** Normalized database-native table comment. */
comment: string | null;
/** Columns sorted by physical name for deterministic serialization. */
columns: SchemaColumn[];
/** Indexes sorted by stable database name. */
indexes: SchemaIndex[];
/** Foreign keys sorted by stable database name. */
foreignKeys: SchemaForeignKey[];
}
/**
* Serializable desired database state collected from ActiveRecord models.
*
* Snapshots deliberately contain no model imports or executable values so an
* old migration remains reproducible after application models change.
*/
export interface SchemaSnapshot {
/** Snapshot format used to support future schema-tool upgrades. */
formatVersion: 1;
/** Database dialect used to resolve model field types. */
dialect: DatabaseDialectName;
/** Model-owned tables sorted by physical database name. */
tables: SchemaTable[];
}
Migration errors
ts
import type { SchemaMigrationPlan } from './contracts/index.js';
/**
* Error raised when another process already owns the source-generation lock.
*/
export declare class DatabaseMigrationLockError extends Error {
readonly lockFile: string;
/**
* Creates a generation-lock contention error.
*
* @param lockFile - Absolute lock file currently owned by another process.
*/
constructor(lockFile: string);
}
/**
* Error raised when an existing untracked database cannot safely adopt the
* sole initial migration without executing its DDL.
*/
export declare class DatabaseMigrationBaselineError extends Error {
readonly plan: SchemaMigrationPlan;
/**
* Creates a baseline mismatch error with its structured schema differences.
*
* @param plan - Differences between the existing database and initial snapshot.
*/
constructor(plan: SchemaMigrationPlan);
}
/**
* Error raised when a source-writing operation is attempted in production.
*/
export declare class DatabaseMigrationSourceGenerationError extends Error {
/**
* Creates a production source-generation policy error.
*/
constructor();
}
Collect model schema
ts
import type { ActiveRecordClass } from '../ActiveRecord.js';
import type { DatabaseDialect } from '../dialects/index.js';
import type { SchemaSnapshot, SchemaValue } from './contracts/index.js';
/**
* Collects a deterministic serializable schema snapshot from ActiveRecord
* model metadata.
*
* @param models - Complete model registry owned by the application.
* @param dialect - Database dialect used by fields to resolve physical types.
* @returns Normalized desired database state sorted by physical names.
*/
export declare function collectModelSchema(models: readonly ActiveRecordClass[], dialect: DatabaseDialect): SchemaSnapshot;
/**
* Canonicalizes dialect type strings so snapshots do not change because of
* harmless whitespace, case, or MariaDB integer display widths.
*
* @param input - Dialect-provided or database-inspected SQL type.
* @returns Stable lower-case SQL type.
*/
export declare function normalizeSchemaColumnType(input: string): string;
/**
* Converts a static field default to the JSON-safe representation permitted in
* committed snapshots and generated migration source.
*
* @param input - Static database default produced by a field.
* @param path - Human-readable location used in validation errors.
* @returns Deterministically ordered JSON-safe value.
*/
export declare function normalizeSchemaValue(input: unknown, path: string): SchemaValue;
Inspect live schema
ts
import type { Knex } from 'knex';
import type { DatabaseDialect } from '../dialects/index.js';
import type { SchemaSnapshot } from './contracts/index.js';
/**
* Reads the model-owned subset of a live MariaDB database into the same
* normalized representation used by model snapshots.
*
* Extra database objects are intentionally ignored. This lets an older
* blue/green application release accept additive objects introduced by a newer
* release while still detecting missing or incompatible requirements. Database
* comments are treated as non-runtime metadata: committed snapshots retain
* them, while compatibility checks ignore live comment drift.
*
* @param db - Knex connection used for information-schema reads.
* @param desired - Current model snapshot defining objects that must be checked.
* @param dialect - MariaDB dialect metadata and index inspection functions.
* @returns Live model-owned database state.
*/
export declare function inspectDatabaseSchema(db: Knex, desired: SchemaSnapshot, dialect: DatabaseDialect): Promise<SchemaSnapshot>;
Compare snapshots
ts
import type { SchemaMigrationPlan, SchemaSnapshot } from './contracts/index.js';
/**
* Computes a pure deterministic migration plan between two normalized schema
* snapshots.
*
* The automatic policy is intentionally conservative. Any blocked change
* prevents the manager from emitting a partially correct migration.
*
* @param from - Previously committed or currently installed model-owned state.
* @param to - New desired model-owned state.
* @returns Safe renderable changes and blocked reviewed changes.
*/
export declare function diffSchemaSnapshots(from: SchemaSnapshot, to: SchemaSnapshot): SchemaMigrationPlan;
Render frozen migrations
ts
import type { SchemaMigrationPlan } from './contracts/index.js';
/**
* Renders a frozen TypeScript Knex migration from a safe schema plan.
*
* Generated source contains literal table, column, index, and foreign-key
* operations. It never imports current models or field implementations.
*
* @param plan - Pure schema plan with no blocked changes.
* @returns Deterministic TypeScript migration source.
*/
export declare function renderKnexMigration(plan: SchemaMigrationPlan): string;
Serialize snapshots
ts
import type { DatabaseDialectName } from '../dialects/index.js';
import type { SchemaSnapshot } from './contracts/index.js';
/**
* Creates an empty normalized snapshot for an application with no models.
*
* @param dialect - Database dialect represented by the snapshot.
* @returns Empty schema snapshot suitable as the first diff baseline.
*/
export declare function emptySchemaSnapshot(dialect: DatabaseDialectName): SchemaSnapshot;
/**
* Serializes a normalized snapshot in the committed human-readable format.
*
* @param snapshot - Normalized schema snapshot.
* @returns Deterministic JSON document ending with one newline.
*/
export declare function serializeSchemaSnapshot(snapshot: SchemaSnapshot): string;
/**
* Parses and minimally validates a committed schema snapshot.
*
* @param input - JSON text read from the application snapshot file.
* @returns Parsed version-one schema snapshot.
*/
export declare function parseSchemaSnapshot(input: string): SchemaSnapshot;
/**
* Produces a stable content hash for migration lineage and comparisons.
*
* @param snapshot - Normalized schema snapshot.
* @returns Lower-case SHA-256 digest.
*/
export declare function hashSchemaSnapshot(snapshot: SchemaSnapshot): string;
Schema naming
ts
import type { SchemaIndexColumn } from './contracts/index.js';
/**
* Builds the stable name used for a model-owned database index.
*
* @param tableName - Physical database table name.
* @param columns - Ordered columns included in the index.
* @param unique - Whether the index enforces uniqueness.
* @param type - Normal or vector database index type.
* @returns MariaDB-safe deterministic index name.
*/
export declare function defaultSchemaIndexName(tableName: string, columns: readonly SchemaIndexColumn[], unique: boolean, type: 'normal' | 'vector'): string;
/**
* Builds the stable name used for a model-owned foreign-key constraint.
*
* @param tableName - Physical database table name.
* @param columnName - Local physical database column.
* @returns MariaDB-safe deterministic foreign-key name.
*/
export declare function defaultSchemaForeignKeyName(tableName: string, columnName: string): string;
/**
* Truncates an identifier with a stable hash while respecting MariaDB's
* 64-character identifier limit.
*
* @param identifier - Preferred human-readable identifier.
* @returns Original or deterministically shortened identifier.
*/
export declare function fitSchemaIdentifier(identifier: string): string;
Explicit destructive promotion
ts
import type { SchemaMigrationPlan } from './contracts/index.js';
/**
* Promotes reviewed destructive removals into safe renderable changes.
*
* Non-destructive blocked operations (type changes, required-column adds, and
* similar) remain blocked so accidental data-loss still requires a review.
*
* @param plan - Diff plan that may contain blocked removals.
* @returns Plan with promoted drop operations, or the original plan when nothing
* could be promoted / remaining blocked changes still exist.
*/
export declare function promoteDestructiveSchemaChanges(plan: SchemaMigrationPlan): SchemaMigrationPlan;
/**
* Reports whether a plan still contains only promotable destructive removals.
*
* @param plan - Diff plan before promotion.
* @returns True when every blocked change can be turned into a drop.
*/
export declare function planHasOnlyPromotableDestructiveChanges(plan: SchemaMigrationPlan): boolean;