Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.8 KiB
@suaveplan/api-migrations - Database-agnostic migration runner for the Suaveplan API — narrow MigrationAdapter surface with per-dialect DDL bootstrap, real SHA-256 checksum validation against on-disk files, AbortSignal cancellation between migrations, OTel counter + histogram per apply, MigrationError with six MIGRATION.* codes. Ships three adapters (surrealql, postgres, sqlite); MySQL slot reserved in the dialect union. Server-tier — Bun + Node.
Database-agnostic migration runner for the Suaveplan API. Ships a narrow
MigrationAdapter surface (six methods), three shipped adapters (surrealql,
postgres, sqlite), a MigrationRunner class that ACTUALLY validates
SHA-256 checksums against on-disk migration files before each apply phase,
AbortSignal propagation between migrations, OTel counter + histogram per
apply attempt, and MigrationError with six namespaced MIGRATION.* codes.
Splits and rewrites the upstream @suaveplan/api's database/migration-runner.ts
(331 LOC). fixes baked in:
- Narrow
MigrationAdaptersurface — the runner depends on six methods, not the wholeDatabaseLike. Each adapter ships its ownensureTableDDL. - Checksums are ACTUALLY validated — drift halts apply with
MigrationError(MIGRATION.CHECKSUM_DRIFT)and{name, expected, actual}context. Upstream'svalidateChecksums: truewas a no-op; this one isn't. AbortSignalpropagation —runFromDirectory(dir, { signal })honors cancellation between migrations.- OTel counter
migrations.applied_total{dialect, outcome}and histogrammigrations.apply_duration_ms{name}emit on every attempt regardless of success. MigrationError extends SuaveplanError<MigrationErrorCode>viadefineCodes("MIGRATION", [...])— six codes, every one raised from a production call site.
Documentation tree
- postgres — Implements the
MigrationAdaptercontract against any Postgres-wire-protocol server (Postgres ≥ 12, CockroachDB, Yugab…- postgres — Implements the
MigrationAdaptercontract against any Postgres-wire-protocol server (Postgres ≥ 12, CockroachDB, Yugab…
- postgres — Implements the
- sqlite — Implements the
MigrationAdaptercontract for SQLite-family engines. The factorycreateSqliteAdapter(client)accepts…- sqlite — Implements the
MigrationAdaptercontract for SQLite-family engines. The factorycreateSqliteAdapter(client)accepts…
- sqlite — Implements the
- surrealql — Implements the
MigrationAdaptercontract for SurrealDB. The factorycreateSurrealqlAdapter(client)wraps any Surrea…- surrealql — Implements the
MigrationAdaptercontract for SurrealDB. The factorycreateSurrealqlAdapter(client)wraps any Surrea…
- surrealql — Implements the
- error-codes — Defines the stable, namespaced error registry for
@suaveplan/api-migrations. Every public failure path in the package…- error-codes — Defines the stable, namespaced error registry for
@suaveplan/api-migrations. Every public failure path in the package…
- error-codes — Defines the stable, namespaced error registry for
- otel — Lazily builds and caches the two OpenTelemetry instruments that
@suaveplan/api-migrationsemits on every migration ap…- instruments — Lazily builds and caches the two OpenTelemetry instruments that
@suaveplan/api-migrationsemits on every migration ap…
- instruments — Lazily builds and caches the two OpenTelemetry instruments that
- runner — The
MigrationRunneris the dialect-agnostic core of the package. It reads migration files from a directory, sorts the…- runner — The
MigrationRunneris the dialect-agnostic core of the package. It reads migration files from a directory, sorts the…
- runner — The
- types — Declares every shared type that the runner, adapters, and consumers exchange across the
@suaveplan/api-migrationspac…- migration — Declares every shared type that the runner, adapters, and consumers exchange across the
@suaveplan/api-migrationspac…
- migration — Declares every shared type that the runner, adapters, and consumers exchange across the
Install
bun add @suaveplan/api-migrations
Quick start
import { MigrationRunner } from "@suaveplan/api-migrations/runner/runner";
import { createSqliteAdapter } from "@suaveplan/api-migrations/adapters/sqlite/sqlite";
const runner = new MigrationRunner(createSqliteAdapter(client), {
fileExtension: ".sql",
});
const controller = new AbortController();
const results = await runner.runFromDirectory("./db/migrations", {
signal: controller.signal,
});
for (const r of results) {
if (!r.success) throw new Error(`Apply halted at ${r.name}: ${r.error}`);
}
Checksum-drift recovery
When validateChecksums: true (default) and a previously applied
migration's on-disk content has changed, the runner halts before applying
any pending migration:
try {
await runner.runFromDirectory("./db/migrations");
} catch (err) {
if (
err instanceof MigrationError &&
err.code === MIGRATION_CODES.CHECKSUM_DRIFT
) {
// err.context = { name, expected, actual }
// Resolution:
// 1. Restore the migration file to its applied form (`git checkout`
// the file at the commit it was applied from).
// 2. If the change is intentional, ship a NEW migration file with
// the additive change. Never rewrite history.
}
throw err;
}
Modules
runner/runner—MigrationRunnerclass +createMigrationRunnerfactory +computeChecksum.adapters/surrealql/surrealql— SurrealDB adapter with SurrealQL DDL.adapters/postgres/postgres— PostgreSQL adapter with standard SQL DDL.adapters/sqlite/sqlite— SQLite adapter compatible withsqlite-wasm/bun:sqlite/better-sqlite3.otel/instruments— counter + histogram.error-codes/error-codes— sixMIGRATION.*codes +MigrationError.types/migration— public type surface.
Subpath exports
Every feature module is independently importable for maximum tree-shakeability:
import { MigrationRunner } from "@suaveplan/api-migrations/runner/runner";
import { createPostgresAdapter } from "@suaveplan/api-migrations/adapters/postgres/postgres";
import { MIGRATION_CODES } from "@suaveplan/api-migrations/error-codes/error-codes";
Tier
Server (Bun + Node). Uses node:crypto for SHA-256 and node:fs/promises
for directory scanning and file reads.