summaryrefslogtreecommitdiff
path: root/apps/web/src/services/storage/migrations/runner.ts
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-03-27 00:55:15 +0100
committerMaze Winther <mazewinther@gmail.com>2026-03-29 15:56:48 +0200
commit4d127a038bf768eded68aae3cfa5c1b12241bdac (patch)
tree16bbb801caf6770546cff4fdb37b6408ec9ead98 /apps/web/src/services/storage/migrations/runner.ts
parent82817cb50cb0487350573d6129130aec705f924b (diff)
downloadopencut-4d127a038bf768eded68aae3cfa5c1b12241bdac.tar.gz
chore: normalize line endings
Diffstat (limited to 'apps/web/src/services/storage/migrations/runner.ts')
-rw-r--r--apps/web/src/services/storage/migrations/runner.ts310
1 files changed, 155 insertions, 155 deletions
diff --git a/apps/web/src/services/storage/migrations/runner.ts b/apps/web/src/services/storage/migrations/runner.ts
index e1c2d09a..409a8695 100644
--- a/apps/web/src/services/storage/migrations/runner.ts
+++ b/apps/web/src/services/storage/migrations/runner.ts
@@ -1,155 +1,155 @@
-import {
- IndexedDBAdapter,
- deleteDatabase,
-} from "@/services/storage/indexeddb-adapter";
-import type { StorageMigration } from "./base";
-import type { ProjectRecord } from "./transformers/types";
-import { getProjectId, isRecord } from "./transformers/utils";
-
-export interface StorageMigrationResult {
- migratedCount: number;
-}
-
-export interface MigrationProgress {
- isMigrating: boolean;
- fromVersion: number | null;
- toVersion: number | null;
- projectName: string | null;
-}
-
-let hasCleanedUpMetaDb = false;
-
-const MIN_MIGRATION_DISPLAY_MS = 1000;
-
-export async function runStorageMigrations({
- migrations,
- onProgress,
-}: {
- migrations: StorageMigration[];
- onProgress?: (progress: MigrationProgress) => void;
-}): Promise<StorageMigrationResult> {
- // 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
- }
- hasCleanedUpMetaDb = true;
- }
-
- const projectsAdapter = new IndexedDBAdapter<ProjectRecord>(
- "video-editor-projects",
- "projects",
- 1,
- );
- const projects = await projectsAdapter.getAll();
-
- const orderedMigrations = [...migrations].sort((a, b) => a.from - b.from);
- let migratedCount = 0;
- let migrationStartTime: number | null = null;
-
- for (const project of projects) {
- if (typeof project !== "object" || project === null) {
- continue;
- }
-
- let projectRecord = project as ProjectRecord;
- let currentVersion = getProjectVersion({ project: projectRecord });
- const targetVersion = orderedMigrations.at(-1)?.to ?? currentVersion;
-
- if (currentVersion >= targetVersion) {
- continue;
- }
-
- // Track when we first showed the migration dialog
- if (migrationStartTime === null) {
- migrationStartTime = Date.now();
- }
-
- const projectName = getProjectName({ project: projectRecord });
- onProgress?.({
- isMigrating: true,
- fromVersion: currentVersion,
- toVersion: targetVersion,
- projectName,
- });
-
- for (const migration of orderedMigrations) {
- if (migration.from !== currentVersion) {
- continue;
- }
-
- const result = await migration.transform(projectRecord);
-
- if (result.skipped) {
- break;
- }
-
- const projectId = getProjectId({ project: result.project });
- if (!projectId) {
- break;
- }
-
- await projectsAdapter.set(projectId, result.project);
- migratedCount++;
- currentVersion = migration.to;
- projectRecord = result.project;
- }
- }
-
- // Ensure dialog is visible for minimum time so users can see it
- if (migrationStartTime !== null) {
- const elapsed = Date.now() - migrationStartTime;
- if (elapsed < MIN_MIGRATION_DISPLAY_MS) {
- await new Promise((resolve) =>
- setTimeout(resolve, MIN_MIGRATION_DISPLAY_MS - elapsed),
- );
- }
- }
-
- onProgress?.({
- isMigrating: false,
- fromVersion: null,
- toVersion: null,
- projectName: null,
- });
-
- return { migratedCount };
-}
-
-function getProjectVersion({ project }: { project: ProjectRecord }): number {
- const versionValue = project.version;
-
- // v2 and up - has explicit version field
- if (typeof versionValue === "number") {
- return versionValue;
- }
-
- // v1 - has scenes array
- const scenesValue = project.scenes;
- if (Array.isArray(scenesValue) && scenesValue.length > 0) {
- return 1;
- }
-
- // v0 - no scenes
- return 0;
-}
-
-function getProjectName({
- project,
-}: {
- project: ProjectRecord;
-}): string | null {
- const metadata = project.metadata;
- if (isRecord(metadata) && typeof metadata.name === "string") {
- return metadata.name;
- }
-
- // v0 had name directly on project
- if (typeof project.name === "string") {
- return project.name;
- }
-
- return null;
-}
+import {
+ IndexedDBAdapter,
+ deleteDatabase,
+} from "@/services/storage/indexeddb-adapter";
+import type { StorageMigration } from "./base";
+import type { ProjectRecord } from "./transformers/types";
+import { getProjectId, isRecord } from "./transformers/utils";
+
+export interface StorageMigrationResult {
+ migratedCount: number;
+}
+
+export interface MigrationProgress {
+ isMigrating: boolean;
+ fromVersion: number | null;
+ toVersion: number | null;
+ projectName: string | null;
+}
+
+let hasCleanedUpMetaDb = false;
+
+const MIN_MIGRATION_DISPLAY_MS = 1000;
+
+export async function runStorageMigrations({
+ migrations,
+ onProgress,
+}: {
+ migrations: StorageMigration[];
+ onProgress?: (progress: MigrationProgress) => void;
+}): Promise<StorageMigrationResult> {
+ // 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
+ }
+ hasCleanedUpMetaDb = true;
+ }
+
+ const projectsAdapter = new IndexedDBAdapter<ProjectRecord>(
+ "video-editor-projects",
+ "projects",
+ 1,
+ );
+ const projects = await projectsAdapter.getAll();
+
+ const orderedMigrations = [...migrations].sort((a, b) => a.from - b.from);
+ let migratedCount = 0;
+ let migrationStartTime: number | null = null;
+
+ for (const project of projects) {
+ if (typeof project !== "object" || project === null) {
+ continue;
+ }
+
+ let projectRecord = project as ProjectRecord;
+ let currentVersion = getProjectVersion({ project: projectRecord });
+ const targetVersion = orderedMigrations.at(-1)?.to ?? currentVersion;
+
+ if (currentVersion >= targetVersion) {
+ continue;
+ }
+
+ // Track when we first showed the migration dialog
+ if (migrationStartTime === null) {
+ migrationStartTime = Date.now();
+ }
+
+ const projectName = getProjectName({ project: projectRecord });
+ onProgress?.({
+ isMigrating: true,
+ fromVersion: currentVersion,
+ toVersion: targetVersion,
+ projectName,
+ });
+
+ for (const migration of orderedMigrations) {
+ if (migration.from !== currentVersion) {
+ continue;
+ }
+
+ const result = await migration.transform(projectRecord);
+
+ if (result.skipped) {
+ break;
+ }
+
+ const projectId = getProjectId({ project: result.project });
+ if (!projectId) {
+ break;
+ }
+
+ await projectsAdapter.set(projectId, result.project);
+ migratedCount++;
+ currentVersion = migration.to;
+ projectRecord = result.project;
+ }
+ }
+
+ // Ensure dialog is visible for minimum time so users can see it
+ if (migrationStartTime !== null) {
+ const elapsed = Date.now() - migrationStartTime;
+ if (elapsed < MIN_MIGRATION_DISPLAY_MS) {
+ await new Promise((resolve) =>
+ setTimeout(resolve, MIN_MIGRATION_DISPLAY_MS - elapsed),
+ );
+ }
+ }
+
+ onProgress?.({
+ isMigrating: false,
+ fromVersion: null,
+ toVersion: null,
+ projectName: null,
+ });
+
+ return { migratedCount };
+}
+
+function getProjectVersion({ project }: { project: ProjectRecord }): number {
+ const versionValue = project.version;
+
+ // v2 and up - has explicit version field
+ if (typeof versionValue === "number") {
+ return versionValue;
+ }
+
+ // v1 - has scenes array
+ const scenesValue = project.scenes;
+ if (Array.isArray(scenesValue) && scenesValue.length > 0) {
+ return 1;
+ }
+
+ // v0 - no scenes
+ return 0;
+}
+
+function getProjectName({
+ project,
+}: {
+ project: ProjectRecord;
+}): string | null {
+ const metadata = project.metadata;
+ if (isRecord(metadata) && typeof metadata.name === "string") {
+ return metadata.name;
+ }
+
+ // v0 had name directly on project
+ if (typeof project.name === "string") {
+ return project.name;
+ }
+
+ return null;
+}