From d55d2583a71ae35fa8d0d1bfbec975e67e66aafa Mon Sep 17 00:00:00 2001 From: cashmere Date: Mon, 27 Jul 2026 01:21:20 +0200 Subject: feat: git-like project versioning (v1) Linear per-project history per notes/project-versioning.md: named checkpoints (thumbnail via renderer.captureFrame) plus auto-checkpoints on save (60s throttle, ring of 20, named never rotate). Restore writes a safety checkpoint first, then swaps the document outside undo/redo. Media assets referenced by any version are pinned against deletion. Migration v31-v32 stamps the schema; the version store lives in its own IDB database with an in-memory fallback for tests. Versions popover in the editor header for jump/rename/delete. 12 new tests. --- .../storage/migrations/transformers/v31-to-v32.ts | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 apps/web/src/services/storage/migrations/transformers/v31-to-v32.ts (limited to 'apps/web/src/services/storage/migrations/transformers') diff --git a/apps/web/src/services/storage/migrations/transformers/v31-to-v32.ts b/apps/web/src/services/storage/migrations/transformers/v31-to-v32.ts new file mode 100644 index 00000000..bedb4784 --- /dev/null +++ b/apps/web/src/services/storage/migrations/transformers/v31-to-v32.ts @@ -0,0 +1,31 @@ +import type { MigrationResult, ProjectRecord } from "./types"; +import { getProjectId } from "./utils"; + +/** + * v31 → v32 introduces the `projectVersions` store (named checkpoints + + * auto-checkpoints; see notes/project-versioning.md). The store lives in its + * own IndexedDB database created lazily by the versions adapter, so project + * records need no shape change — this migration only stamps the new version. + */ +export function transformProjectV31ToV32({ + project, +}: { + project: ProjectRecord; +}): MigrationResult { + 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 >= 32) { + return { project, skipped: true, reason: "already v32" }; + } + if (version !== 31) { + return { project, skipped: true, reason: "not v31" }; + } + + return { project: { ...project, version: 32 }, skipped: false }; +} -- cgit v1.3.1