feat(planner): add bridge target version strategy for auto-stamping ledger to app versions

This commit is contained in:
2026-05-19 21:44:57 +00:00
parent c04a094723
commit b3078029e3
8 changed files with 250 additions and 3 deletions
+51 -1
View File
@@ -23,6 +23,7 @@ const DEFAULT_LOCK_WAIT_MS = 60_000;
const DEFAULT_LOCK_TTL_MS = 600_000;
const LOCK_POLL_INTERVAL_MS = 500;
const MIN_LOCK_HEARTBEAT_MS = 1;
const AUTO_BRIDGE_STEP_ID_PREFIX = 'smartmigration-auto-bridge-to';
interface IResolvedLedgerState {
currentVersionBefore: string | null;
@@ -120,6 +121,18 @@ export class SmartMigration {
});
}
if (
options.targetVersionStrategy !== undefined &&
options.targetVersionStrategy !== 'strict' &&
options.targetVersionStrategy !== 'bridge'
) {
throw new SmartMigrationError(
'INVALID_TARGET_VERSION_STRATEGY',
'targetVersionStrategy must be "strict" or "bridge" when provided.',
{ targetVersionStrategy: options.targetVersionStrategy },
);
}
this.settings = {
targetVersion: options.targetVersion,
db: options.db,
@@ -130,6 +143,7 @@ export class SmartMigration {
lockWaitMs: options.lockWaitMs ?? DEFAULT_LOCK_WAIT_MS,
lockTtlMs: options.lockTtlMs ?? DEFAULT_LOCK_TTL_MS,
dryRun: options.dryRun ?? false,
targetVersionStrategy: options.targetVersionStrategy ?? 'strict',
logger: options.logger,
};
@@ -443,13 +457,14 @@ export class SmartMigration {
effectiveCurrentVersion = data.currentVersion;
}
const planningSteps = this.getPlanningSteps(effectiveCurrentVersion);
const plannedSteps = VersionResolver.equals(
effectiveCurrentVersion,
this.settings.targetVersion,
)
? []
: VersionResolver.computePlan(
this.steps,
planningSteps,
effectiveCurrentVersion,
this.settings.targetVersion,
);
@@ -468,6 +483,41 @@ export class SmartMigration {
};
}
private getPlanningSteps(effectiveCurrentVersion: string): IMigrationStepDefinition[] {
if (this.settings.targetVersionStrategy === 'strict') {
return this.steps;
}
const targetVersion = this.settings.targetVersion;
if (this.steps.length === 0) {
return VersionResolver.lessThan(effectiveCurrentVersion, targetVersion)
? [this.createAutoBridgeStep(effectiveCurrentVersion, targetVersion)]
: [];
}
const lastStep = this.steps[this.steps.length - 1];
if (!VersionResolver.lessThan(lastStep.toVersion, targetVersion)) {
return this.steps;
}
return [
...this.steps,
this.createAutoBridgeStep(lastStep.toVersion, targetVersion),
];
}
private createAutoBridgeStep(fromVersion: string, toVersion: string): IMigrationStepDefinition {
return {
id: `${AUTO_BRIDGE_STEP_ID_PREFIX}-${toVersion}`,
fromVersion,
toVersion,
description: `Auto bridge migration ledger to target version ${toVersion}`,
isResumable: false,
isVirtual: true,
handler: async () => {},
};
}
private async ensureLedger(): Promise<Ledger> {
if (this.ledger) return this.ledger;
const ledgerName = this.settings.ledgerName;