summaryrefslogtreecommitdiff
path: root/apps/web/src/services/storage/migrations/runner.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/services/storage/migrations/runner.ts')
-rw-r--r--apps/web/src/services/storage/migrations/runner.ts150
1 files changed, 53 insertions, 97 deletions
diff --git a/apps/web/src/services/storage/migrations/runner.ts b/apps/web/src/services/storage/migrations/runner.ts
index cbc3739f..83e7edae 100644
--- a/apps/web/src/services/storage/migrations/runner.ts
+++ b/apps/web/src/services/storage/migrations/runner.ts
@@ -1,138 +1,94 @@
-import { IndexedDBAdapter } from "@/services/storage/indexeddb-adapter";
+import {
+ IndexedDBAdapter,
+ deleteDatabase,
+} from "@/services/storage/indexeddb-adapter";
import type { StorageMigration } from "./base";
-import { StorageVersionManager } from "./version-manager";
+import type { ProjectRecord } from "./transformers/types";
+import { getProjectId } from "./transformers/utils";
export interface StorageMigrationResult {
- fromVersion: number;
- toVersion: number;
- migrated: boolean;
+ migratedCount: number;
}
-export type StorageMigrationCallbacks = {
- onMigrationStart?: ({
- fromVersion,
- toVersion,
- }: {
- fromVersion: number;
- toVersion: number;
- }) => void;
- onMigrationComplete?: ({
- fromVersion,
- toVersion,
- }: {
- fromVersion: number;
- toVersion: number;
- }) => void;
-};
-
-type ProjectRecord = Record<string, unknown>;
+let hasCleanedUpMetaDb = false;
export async function runStorageMigrations({
migrations,
- versionManager = new StorageVersionManager(),
- callbacks,
}: {
migrations: StorageMigration[];
- versionManager?: StorageVersionManager;
- callbacks?: StorageMigrationCallbacks;
}): Promise<StorageMigrationResult> {
- 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;
+ // One-time cleanup: delete the old global version database
+ if (!hasCleanedUpMetaDb) {
+ try {
+ await deleteDatabase({ dbName: "video-editor-meta" });
+ } catch {
+ // Ignore errors - DB might not exist
}
-
- 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,
- });
+ hasCleanedUpMetaDb = true;
}
- return {
- fromVersion,
- toVersion: currentVersion,
- migrated: currentVersion !== fromVersion,
- };
-}
-
-async function inferStorageVersionFromProjects(): Promise<number> {
- const projectsAdapter = new IndexedDBAdapter<unknown>(
+ const projectsAdapter = new IndexedDBAdapter<ProjectRecord>(
"video-editor-projects",
"projects",
1,
);
const projects = await projectsAdapter.getAll();
- if (projects.length === 0) {
- return 0;
- }
-
- let lowestVersion = Number.POSITIVE_INFINITY;
+ const orderedMigrations = [...migrations].sort((a, b) => a.from - b.from);
+ let migratedCount = 0;
for (const project of projects) {
- const projectVersion = checkProjectVersion({ project });
- if (projectVersion < lowestVersion) {
- lowestVersion = projectVersion;
+ if (typeof project !== "object" || project === null) {
+ continue;
}
- }
- if (lowestVersion === Number.POSITIVE_INFINITY) {
- return 0;
- }
+ let projectRecord = project as ProjectRecord;
+ let currentVersion = getProjectVersion({ project: projectRecord });
- return lowestVersion;
-}
+ // Apply migrations sequentially until project is up to date
+ for (const migration of orderedMigrations) {
+ if (migration.from !== currentVersion) {
+ continue;
+ }
+
+ const result = await migration.transform(projectRecord);
+
+ if (result.skipped) {
+ break; // Project is already at this version or higher
+ }
+
+ // Update project with migrated version
+ const projectId = getProjectId({ project: result.project });
+ if (!projectId) {
+ break; // Can't save without ID
+ }
-function checkProjectVersion({ project }: { project: unknown }): number {
- if (!isRecord(project)) {
- return 0;
+ await projectsAdapter.set(projectId, result.project);
+ migratedCount++;
+ currentVersion = migration.to;
+
+ // Use migrated project for next iteration
+ projectRecord = result.project;
+ }
}
+ return { migratedCount };
+}
+
+function getProjectVersion({ project }: { project: ProjectRecord }): number {
const versionValue = project.version;
- // v2 and up
+ // v2 and up - has explicit version field
if (typeof versionValue === "number") {
return versionValue;
}
- // v1 (got scenes)
+ // v1 - has scenes array
const scenesValue = project.scenes;
if (Array.isArray(scenesValue) && scenesValue.length > 0) {
return 1;
}
- // v0 (didn't have scenes)
+ // v0 - no scenes
return 0;
}
-
-function isRecord(value: unknown): value is ProjectRecord {
- return typeof value === "object" && value !== null;
-}