feat(smartmigration): add initial smartmigration package with MongoDB and S3 migration runner
This commit is contained in:
169
ts/interfaces.ts
Normal file
169
ts/interfaces.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import type * as plugins from './plugins.js';
|
||||
import type { TLedgerBackend, TMigrationStatus } from './types.js';
|
||||
|
||||
/**
|
||||
* Constructor options for SmartMigration.
|
||||
*/
|
||||
export interface ISmartMigrationOptions {
|
||||
/** Target version for the data. Typically the app's package.json version. */
|
||||
targetVersion: string;
|
||||
|
||||
/**
|
||||
* Optional smartdata instance. Required if any step uses ctx.db / ctx.mongo,
|
||||
* and required if you want a mongo-backed ledger.
|
||||
*/
|
||||
db?: plugins.smartdata.SmartdataDb;
|
||||
|
||||
/**
|
||||
* Optional smartbucket Bucket. Required if any step uses ctx.bucket / ctx.s3,
|
||||
* and required if you want an S3-backed ledger.
|
||||
*/
|
||||
bucket?: plugins.smartbucket.Bucket;
|
||||
|
||||
/** Logical name for this migration ledger. Defaults to "smartmigration". */
|
||||
ledgerName?: string;
|
||||
|
||||
/** Where to persist the ledger. Defaults to "mongo" if db provided, otherwise "s3". */
|
||||
ledgerBackend?: TLedgerBackend;
|
||||
|
||||
/**
|
||||
* For a fresh install (no ledger AND no app data), jump straight to this version
|
||||
* instead of running every step from the earliest. Defaults to undefined,
|
||||
* which means "run every step from earliest from-version".
|
||||
*/
|
||||
freshInstallVersion?: string;
|
||||
|
||||
/** How long (ms) to wait for a stale lock from another instance. Default 60_000. */
|
||||
lockWaitMs?: number;
|
||||
|
||||
/** How long (ms) before this instance's own lock auto-expires. Default 600_000. */
|
||||
lockTtlMs?: number;
|
||||
|
||||
/** If true, run() returns the plan without executing anything. Default false. */
|
||||
dryRun?: boolean;
|
||||
|
||||
/** Custom logger. Defaults to module logger. */
|
||||
logger?: plugins.smartlog.Smartlog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about a single step exposed to the migration handler via ctx.step.
|
||||
*/
|
||||
export interface IMigrationStepInfo {
|
||||
id: string;
|
||||
fromVersion: string;
|
||||
toVersion: string;
|
||||
description?: string;
|
||||
isResumable: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* The context object passed into every step's `up()` handler.
|
||||
*/
|
||||
export interface IMigrationContext {
|
||||
/** High-level smartdata instance. Present iff `db` was passed to the constructor. */
|
||||
db?: plugins.smartdata.SmartdataDb;
|
||||
|
||||
/** High-level smartbucket Bucket. Present iff `bucket` was passed to the constructor. */
|
||||
bucket?: plugins.smartbucket.Bucket;
|
||||
|
||||
/** Raw mongo `Db`. Present iff `db` was passed to the constructor. */
|
||||
mongo?: plugins.TRawMongoDb;
|
||||
|
||||
/** Raw S3 client. Present iff `bucket` was passed to the constructor. */
|
||||
s3?: plugins.TRawS3Client;
|
||||
|
||||
/** Metadata about the currently running step. */
|
||||
step: IMigrationStepInfo;
|
||||
|
||||
/** Logger scoped to this run. */
|
||||
log: plugins.smartlog.Smartlog;
|
||||
|
||||
/** True when run() was called with `dryRun: true`. */
|
||||
isDryRun: boolean;
|
||||
|
||||
/** Only present when the step was marked `.resumable()`. */
|
||||
checkpoint?: IMigrationCheckpoint;
|
||||
|
||||
/** Convenience for transactional mongo migrations. Throws if no db configured. */
|
||||
startSession(): plugins.TMongoClientSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-step persistent key/value store, used by resumable migrations to
|
||||
* record progress so a subsequent run can pick up where the previous one
|
||||
* stopped.
|
||||
*/
|
||||
export interface IMigrationCheckpoint {
|
||||
read<T = unknown>(key: string): Promise<T | undefined>;
|
||||
write<T = unknown>(key: string, value: T): Promise<void>;
|
||||
clear(): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The serialized form of a migration step's outcome, as stored in the ledger.
|
||||
*/
|
||||
export interface IMigrationLedgerEntry {
|
||||
id: string;
|
||||
fromVersion: string;
|
||||
toVersion: string;
|
||||
status: TMigrationStatus;
|
||||
startedAt: string;
|
||||
finishedAt: string;
|
||||
durationMs: number;
|
||||
error?: { message: string; stack?: string };
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-step result returned by run().
|
||||
*/
|
||||
export interface IMigrationStepResult {
|
||||
id: string;
|
||||
fromVersion: string;
|
||||
toVersion: string;
|
||||
status: TMigrationStatus;
|
||||
durationMs: number;
|
||||
startedAt: string;
|
||||
finishedAt: string;
|
||||
error?: { message: string; stack?: string };
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of a single call to SmartMigration.run() or .plan().
|
||||
*/
|
||||
export interface IMigrationRunResult {
|
||||
currentVersionBefore: string | null;
|
||||
currentVersionAfter: string;
|
||||
targetVersion: string;
|
||||
wasUpToDate: boolean;
|
||||
wasFreshInstall: boolean;
|
||||
stepsApplied: IMigrationStepResult[];
|
||||
stepsSkipped: IMigrationStepResult[];
|
||||
totalDurationMs: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* The opaque definition of a registered step. Created by MigrationStepBuilder.
|
||||
*/
|
||||
export interface IMigrationStepDefinition {
|
||||
id: string;
|
||||
fromVersion: string;
|
||||
toVersion: string;
|
||||
description?: string;
|
||||
isResumable: boolean;
|
||||
handler: (ctx: IMigrationContext) => Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal: the shape of the data persisted in the ledger backend.
|
||||
*/
|
||||
export interface ISmartMigrationLedgerData {
|
||||
currentVersion: string | null;
|
||||
steps: Record<string, IMigrationLedgerEntry>;
|
||||
lock: {
|
||||
holder: string | null;
|
||||
acquiredAt: string | null;
|
||||
expiresAt: string | null;
|
||||
};
|
||||
checkpoints: Record<string, Record<string, unknown>>;
|
||||
}
|
||||
Reference in New Issue
Block a user