mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
PM-3585 Improve state migrations (#5009)
* WIP: safer state migrations Co-authored-by: Justin Baur <justindbaur@users.noreply.github.com> * Add min version check and remove old migrations Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * Add rollback and version checking * Add state version move migration * Expand tests and improve typing for Migrations * Remove StateMigration Service * Rewrite version 5 and 6 migrations * Add all but initial migration to supported migrations * Handle stateVersion location in migrator update versions * Move to unique migrations directory * Disallow imports outside of state-migrations * Lint and test fixes * Do not run migrations if we cannot determine state * Fix desktop background StateService build * Document Migration builder class * Add debug logging to migrations * Comment on migrator overrides * Use specific property names * `npm run prettier` 🤖 * Insert new migration * Set stateVersion when creating new globals object * PR comments * Fix migrate imports * Move migration building into `migrate` function * Export current version from migration definitions * Move file version concerns to migrator * Update migrate spec to reflect new version requirements * Fix import paths * Prefer unique state data * Remove unnecessary async * Prefer to not use `any` --------- Co-authored-by: Justin Baur <justindbaur@users.noreply.github.com> Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com>
This commit is contained in:
40
libs/common/src/state-migrations/migrator.ts
Normal file
40
libs/common/src/state-migrations/migrator.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { NonNegativeInteger } from "type-fest";
|
||||
|
||||
import { MigrationHelper } from "./migration-helper";
|
||||
|
||||
export const IRREVERSIBLE = new Error("Irreversible migration");
|
||||
|
||||
export type VersionFrom<T> = T extends Migrator<infer TFrom, number>
|
||||
? TFrom extends NonNegativeInteger<TFrom>
|
||||
? TFrom
|
||||
: never
|
||||
: never;
|
||||
export type VersionTo<T> = T extends Migrator<number, infer TTo>
|
||||
? TTo extends NonNegativeInteger<TTo>
|
||||
? TTo
|
||||
: never
|
||||
: never;
|
||||
export type Direction = "up" | "down";
|
||||
|
||||
export abstract class Migrator<TFrom extends number, TTo extends number> {
|
||||
constructor(public fromVersion: TFrom, public toVersion: TTo) {
|
||||
if (fromVersion == null || toVersion == null) {
|
||||
throw new Error("Invalid migration");
|
||||
}
|
||||
if (fromVersion > toVersion) {
|
||||
throw new Error("Invalid migration");
|
||||
}
|
||||
}
|
||||
|
||||
shouldMigrate(helper: MigrationHelper, direction: Direction): Promise<boolean> {
|
||||
const startVersion = direction === "up" ? this.fromVersion : this.toVersion;
|
||||
return Promise.resolve(helper.currentVersion === startVersion);
|
||||
}
|
||||
abstract migrate(helper: MigrationHelper): Promise<void>;
|
||||
abstract rollback(helper: MigrationHelper): Promise<void>;
|
||||
async updateVersion(helper: MigrationHelper, direction: Direction): Promise<void> {
|
||||
const endVersion = direction === "up" ? this.toVersion : this.fromVersion;
|
||||
helper.currentVersion = endVersion;
|
||||
await helper.set("stateVersion", endVersion);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user