1
0
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:
Matt Gibson
2023-08-30 12:57:20 -05:00
committed by GitHub
parent b444eed0b5
commit 3340af8084
51 changed files with 1538 additions and 980 deletions

View 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);
}
}