diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-03-25 16:47:22 +0100 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-03-29 15:48:22 +0200 |
| commit | 8db3bead13441a5882d8689dfc6a9f09c82375d9 (patch) | |
| tree | e9d0cafa93904ffcbec3188c37961bcc16c6422d /apps/web/src/services/storage/service.ts | |
| parent | 39ea298a9ccba3104c549c0ca079c231981811f5 (diff) | |
| download | opencut-8db3bead13441a5882d8689dfc6a9f09c82375d9.tar.gz | |
feat: masks, properties refactor, shaders, storage migrations, and more
Diffstat (limited to 'apps/web/src/services/storage/service.ts')
| -rw-r--r-- | apps/web/src/services/storage/service.ts | 52 |
1 files changed, 45 insertions, 7 deletions
diff --git a/apps/web/src/services/storage/service.ts b/apps/web/src/services/storage/service.ts index aac152da..3a014894 100644 --- a/apps/web/src/services/storage/service.ts +++ b/apps/web/src/services/storage/service.ts @@ -1,20 +1,27 @@ -import type { TProject, TProjectMetadata } from "@/types/project"; +import type { TProject, TProjectMetadata } from "@/lib/project/types"; import { getProjectDurationFromScenes } from "@/lib/scenes"; -import type { MediaAsset } from "@/types/assets"; +import type { MediaAsset } from "@/lib/media/types"; import { IndexedDBAdapter } from "./indexeddb-adapter"; import { OPFSAdapter } from "./opfs-adapter"; +import { + type StorageCapacityCheckResult, + StorageQuotaExceededError, + evaluateStorageCapacity, + isStorageQuotaExceededError, + readStorageQuotaStatus, +} from "./quota"; import type { MediaAssetData, StorageConfig, SerializedProject, SerializedScene, } from "./types"; -import type { SavedSoundsData, SavedSound, SoundEffect } from "@/types/sounds"; +import type { SavedSoundsData, SavedSound, SoundEffect } from "@/lib/sounds/types"; import { migrations, runStorageMigrations, } from "@/services/storage/migrations"; -import type { Bookmark, TimelineTrack, TScene } from "@/types/timeline"; +import type { Bookmark, TimelineTrack, TScene } from "@/lib/timeline"; function normalizeBookmarks({ raw }: { raw: unknown }): Bookmark[] { if (!Array.isArray(raw)) return []; @@ -90,6 +97,22 @@ class StorageService { return { mediaMetadataAdapter, mediaAssetsAdapter }; } + async canStoreFile({ + size, + }: { + size: number; + }): Promise<StorageCapacityCheckResult> { + const quotaStatus = await readStorageQuotaStatus(); + return evaluateStorageCapacity({ + requiredBytes: size, + quotaStatus, + }); + } + + isQuotaExceededError({ error }: { error: unknown }): boolean { + return isStorageQuotaExceededError({ error }); + } + private stripAudioBuffers({ tracks, }: { @@ -238,8 +261,6 @@ class StorageService { const { mediaMetadataAdapter, mediaAssetsAdapter } = this.getProjectMediaAdapters({ projectId }); - await mediaAssetsAdapter.set(mediaAsset.id, mediaAsset.file); - const metadata: MediaAssetData = { id: mediaAsset.id, name: mediaAsset.name, @@ -253,7 +274,24 @@ class StorageService { ephemeral: mediaAsset.ephemeral, }; - await mediaMetadataAdapter.set(mediaAsset.id, metadata); + try { + await mediaAssetsAdapter.set(mediaAsset.id, mediaAsset.file); + await mediaMetadataAdapter.set(mediaAsset.id, metadata); + } catch (error) { + try { + await mediaAssetsAdapter.remove(mediaAsset.id); + } catch { + // Ignore cleanup failures so the original storage error is preserved. + } + + if (this.isQuotaExceededError({ error })) { + throw new StorageQuotaExceededError({ + requiredBytes: mediaAsset.file.size, + }); + } + + throw error; + } } async loadMediaAsset({ |
