summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/web/src/services/storage/migrations/index.ts4
-rw-r--r--apps/web/src/services/storage/migrations/transformers/v23-to-v24.ts17
-rw-r--r--apps/web/src/services/storage/migrations/transformers/v25-to-v26.ts129
-rw-r--r--apps/web/src/services/storage/migrations/v25-to-v26.ts16
4 files changed, 161 insertions, 5 deletions
diff --git a/apps/web/src/services/storage/migrations/index.ts b/apps/web/src/services/storage/migrations/index.ts
index bb2d9709..c5a2e237 100644
--- a/apps/web/src/services/storage/migrations/index.ts
+++ b/apps/web/src/services/storage/migrations/index.ts
@@ -24,10 +24,11 @@ import { V21toV22Migration } from "./v21-to-v22";
import { V22toV23Migration } from "./v22-to-v23";
import { V23toV24Migration } from "./v23-to-v24";
import { V24toV25Migration } from "./v24-to-v25";
+import { V25toV26Migration } from "./v25-to-v26";
export { runStorageMigrations } from "./runner";
export type { MigrationProgress } from "./runner";
-export const CURRENT_PROJECT_VERSION = 25;
+export const CURRENT_PROJECT_VERSION = 26;
export const migrations = [
new V0toV1Migration(),
@@ -55,4 +56,5 @@ export const migrations = [
new V22toV23Migration(),
new V23toV24Migration(),
new V24toV25Migration(),
+ new V25toV26Migration(),
];
diff --git a/apps/web/src/services/storage/migrations/transformers/v23-to-v24.ts b/apps/web/src/services/storage/migrations/transformers/v23-to-v24.ts
index 710d4dc1..736ca8dd 100644
--- a/apps/web/src/services/storage/migrations/transformers/v23-to-v24.ts
+++ b/apps/web/src/services/storage/migrations/transformers/v23-to-v24.ts
@@ -51,9 +51,7 @@ function migrateScene({ scene }: { scene: unknown }): unknown {
}
const mainTrack = findMainTrack({ tracks: scene.tracks });
- if (!mainTrack) {
- return scene;
- }
+ const finalMainTrack = mainTrack ?? buildEmptyMainTrack();
return {
...scene,
@@ -65,7 +63,7 @@ function migrateScene({ scene }: { scene: unknown }): unknown {
(track): track is ProjectRecord =>
isRecord(track) && track.type !== "audio",
),
- main: migrateTrack({ track: mainTrack }),
+ main: migrateTrack({ track: finalMainTrack }),
audio: scene.tracks
.map((track) => migrateTrack({ track }))
.filter(
@@ -76,6 +74,17 @@ function migrateScene({ scene }: { scene: unknown }): unknown {
};
}
+function buildEmptyMainTrack(): ProjectRecord {
+ return {
+ id: crypto.randomUUID(),
+ name: "Main",
+ type: "video",
+ elements: [],
+ muted: false,
+ hidden: false,
+ };
+}
+
function findMainTrack({
tracks,
}: {
diff --git a/apps/web/src/services/storage/migrations/transformers/v25-to-v26.ts b/apps/web/src/services/storage/migrations/transformers/v25-to-v26.ts
new file mode 100644
index 00000000..f00383e6
--- /dev/null
+++ b/apps/web/src/services/storage/migrations/transformers/v25-to-v26.ts
@@ -0,0 +1,129 @@
+import type { MigrationResult, ProjectRecord } from "./types";
+import { getProjectId, isRecord } from "./utils";
+
+export function transformProjectV25ToV26({
+ project,
+}: {
+ project: ProjectRecord;
+}): MigrationResult<ProjectRecord> {
+ if (!getProjectId({ project })) {
+ return { project, skipped: true, reason: "no project id" };
+ }
+
+ const version = project.version;
+ if (typeof version !== "number") {
+ return { project, skipped: true, reason: "invalid version" };
+ }
+ if (version >= 26) {
+ return { project, skipped: true, reason: "already v26" };
+ }
+ if (version !== 25) {
+ return { project, skipped: true, reason: "not v25" };
+ }
+
+ return {
+ project: {
+ ...migrateProject({ project }),
+ version: 26,
+ },
+ skipped: false,
+ };
+}
+
+function migrateProject({
+ project,
+}: {
+ project: ProjectRecord;
+}): ProjectRecord {
+ if (!Array.isArray(project.scenes)) {
+ return project;
+ }
+
+ return {
+ ...project,
+ scenes: project.scenes.map((scene) => migrateScene({ scene })),
+ };
+}
+
+function migrateScene({ scene }: { scene: unknown }): unknown {
+ if (!isRecord(scene)) {
+ return scene;
+ }
+
+ const tracks = scene.tracks;
+
+ // Already in the correct shape — nothing to repair
+ if (isRecord(tracks) && Array.isArray(tracks.overlay) && Array.isArray(tracks.audio)) {
+ return scene;
+ }
+
+ // Reconstruct the flat track array from whatever broken state it's in.
+ // v24-to-v25 spread a flat array into a numeric-keyed object, so
+ // Object.values recovers the original elements. A true flat array is
+ // also handled for safety.
+ let trackArray: unknown[];
+ if (Array.isArray(tracks)) {
+ trackArray = tracks;
+ } else if (isRecord(tracks)) {
+ trackArray = Object.values(tracks);
+ } else {
+ trackArray = [];
+ }
+
+ const mainTrack = findMainTrack({ tracks: trackArray });
+ const finalMainTrack = mainTrack ?? buildEmptyMainTrack();
+
+ return {
+ ...scene,
+ tracks: {
+ main: migrateTrack({ track: finalMainTrack }),
+ overlay: trackArray
+ .filter((track) => track !== mainTrack)
+ .map((track) => migrateTrack({ track }))
+ .filter(
+ (track): track is ProjectRecord =>
+ isRecord(track) && track.type !== "audio",
+ ),
+ audio: trackArray
+ .map((track) => migrateTrack({ track }))
+ .filter(
+ (track): track is ProjectRecord =>
+ isRecord(track) && track.type === "audio",
+ ),
+ },
+ };
+}
+
+function findMainTrack({
+ tracks,
+}: {
+ tracks: unknown[];
+}): ProjectRecord | null {
+ for (const track of tracks) {
+ if (!isRecord(track)) continue;
+ if (track.type === "video" && track.isMain === true) return track;
+ }
+ for (const track of tracks) {
+ if (!isRecord(track)) continue;
+ if (track.type === "video") return track;
+ }
+ return null;
+}
+
+function migrateTrack({ track }: { track: unknown }): unknown {
+ if (!isRecord(track)) return track;
+ const nextTrack = { ...track };
+ delete nextTrack.isMain;
+ return nextTrack;
+}
+
+function buildEmptyMainTrack(): ProjectRecord {
+ return {
+ id: crypto.randomUUID(),
+ name: "Main",
+ type: "video",
+ elements: [],
+ muted: false,
+ hidden: false,
+ };
+}
diff --git a/apps/web/src/services/storage/migrations/v25-to-v26.ts b/apps/web/src/services/storage/migrations/v25-to-v26.ts
new file mode 100644
index 00000000..b5a8f310
--- /dev/null
+++ b/apps/web/src/services/storage/migrations/v25-to-v26.ts
@@ -0,0 +1,16 @@
+import { StorageMigration } from "./base";
+import type { ProjectRecord } from "./transformers/types";
+import { transformProjectV25ToV26 } from "./transformers/v25-to-v26";
+
+export class V25toV26Migration extends StorageMigration {
+ from = 25;
+ to = 26;
+
+ async transform(project: ProjectRecord): Promise<{
+ project: ProjectRecord;
+ skipped: boolean;
+ reason?: string;
+ }> {
+ return transformProjectV25ToV26({ project });
+ }
+}