From 7bf0984698e43b9aa2dd879f65951318ed410390 Mon Sep 17 00:00:00 2001 From: Maze <167211895+mazeincoding@users.noreply.github.com> Date: Sat, 31 Jan 2026 00:20:04 +0100 Subject: codebase overhaul (#697) --- apps/web/src/services/storage/migrations/runner.ts | 134 +++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 apps/web/src/services/storage/migrations/runner.ts (limited to 'apps/web/src/services/storage/migrations/runner.ts') diff --git a/apps/web/src/services/storage/migrations/runner.ts b/apps/web/src/services/storage/migrations/runner.ts new file mode 100644 index 00000000..d9277cb0 --- /dev/null +++ b/apps/web/src/services/storage/migrations/runner.ts @@ -0,0 +1,134 @@ +import { IndexedDBAdapter } from "@/services/storage/indexeddb-adapter"; +import type { StorageMigration } from "./base"; +import { StorageVersionManager } from "./version-manager"; + +export interface StorageMigrationResult { + fromVersion: number; + toVersion: number; + migrated: boolean; +} + +export type StorageMigrationCallbacks = { + onMigrationStart?: ({ + fromVersion, + toVersion, + }: { + fromVersion: number; + toVersion: number; + }) => void; + onMigrationComplete?: ({ + fromVersion, + toVersion, + }: { + fromVersion: number; + toVersion: number; + }) => void; +}; + +type ProjectRecord = Record; + +export async function runStorageMigrations({ + migrations, + versionManager = new StorageVersionManager(), + callbacks, +}: { + migrations: StorageMigration[]; + versionManager?: StorageVersionManager; + callbacks?: StorageMigrationCallbacks; +}): Promise { + const versionRecord = await versionManager.getVersionRecord(); + const inferredVersion = versionRecord + ? null + : await inferStorageVersionFromProjects(); + const fromVersion = + versionRecord?.inProgress?.from ?? + versionRecord?.version ?? + inferredVersion ?? + 0; + + if (!versionRecord) { + await versionManager.setVersion({ version: fromVersion }); + } + + const orderedMigrations = [...migrations].sort((a, b) => a.from - b.from); + let currentVersion = fromVersion; + + for (const migration of orderedMigrations) { + if (migration.from !== currentVersion) { + continue; + } + + await versionManager.setInProgress({ + from: migration.from, + to: migration.to, + }); + callbacks?.onMigrationStart?.({ + fromVersion: migration.from, + toVersion: migration.to, + }); + await migration.run(); + currentVersion = migration.to; + await versionManager.setVersion({ version: currentVersion }); + await versionManager.clearInProgress(); + callbacks?.onMigrationComplete?.({ + fromVersion: migration.from, + toVersion: migration.to, + }); + } + + return { + fromVersion, + toVersion: currentVersion, + migrated: currentVersion !== fromVersion, + }; +} + +async function inferStorageVersionFromProjects(): Promise { + const projectsAdapter = new IndexedDBAdapter( + "video-editor-projects", + "projects", + 1, + ); + const projects = await projectsAdapter.getAll(); + + if (projects.length === 0) { + return 0; + } + + let lowestVersion = Number.POSITIVE_INFINITY; + + for (const project of projects) { + const projectVersion = checkProjectVersion({ project }); + if (projectVersion < lowestVersion) { + lowestVersion = projectVersion; + } + } + + if (lowestVersion === Number.POSITIVE_INFINITY) { + return 0; + } + + return lowestVersion; +} + +function checkProjectVersion({ project }: { project: unknown }): number { + if (!isRecord(project)) { + return 0; + } + + const versionValue = project.version; + if (typeof versionValue === "number") { + return versionValue; + } + + const scenesValue = project.scenes; + if (Array.isArray(scenesValue) && scenesValue.length > 0) { + return 1; + } + + return 0; +} + +function isRecord(value: unknown): value is ProjectRecord { + return typeof value === "object" && value !== null; +} -- cgit v1.3.1