diff --git a/libs/services/src/lib/playlist-storage-backend.spec.ts b/libs/services/src/lib/playlist-storage-backend.spec.ts index dadffd2f3..50c50bd75 100644 --- a/libs/services/src/lib/playlist-storage-backend.spec.ts +++ b/libs/services/src/lib/playlist-storage-backend.spec.ts @@ -41,4 +41,30 @@ describe('PlaylistStorageBackend', () => { expect(backend.kind()).toBe('indexeddb'); expect(backend.documentStore()).toBeNull(); }); + + it('prefers the server store once it is set', () => { + testWindow.electron = undefined; + const backend = create(false); + const store = { dbGetAppPlaylists: jest.fn() } as never; + + backend.useServerStore(store); + + expect(backend.kind()).toBe('server'); + expect(backend.documentStore()).toBe(store); + }); + + it('falls back to browser storage while an override task runs', async () => { + testWindow.electron = undefined; + const backend = create(false); + backend.useServerStore({ dbGetAppPlaylists: jest.fn() } as never); + + const seen = await backend.runWithBrowserStorage(async () => [ + backend.kind(), + backend.usesBrowserStorageOverride(), + ]); + + expect(seen).toEqual(['indexeddb', true]); + expect(backend.kind()).toBe('server'); + expect(backend.usesBrowserStorageOverride()).toBe(false); + }); }); diff --git a/libs/services/src/lib/playlist-storage-backend.ts b/libs/services/src/lib/playlist-storage-backend.ts index ce1653b9d..983c32092 100644 --- a/libs/services/src/lib/playlist-storage-backend.ts +++ b/libs/services/src/lib/playlist-storage-backend.ts @@ -28,20 +28,51 @@ export type PlaylistDocumentStore = Pick< > >; -export type PlaylistStorageKind = 'electron' | 'indexeddb'; +export type PlaylistStorageKind = 'electron' | 'server' | 'indexeddb'; /** Single place that decides where `PlaylistsService` persists playlists. */ @Injectable({ providedIn: 'root' }) export class PlaylistStorageBackend { private readonly runtime = inject(RuntimeCapabilitiesService); + private serverStore: PlaylistDocumentStore | null = null; + private browserOverrideDepth = 0; + + /** Server mode: set once by the server storage session at startup. */ + useServerStore(store: PlaylistDocumentStore): void { + this.serverStore = store; + } + + usesBrowserStorageOverride(): boolean { + return this.browserOverrideDepth > 0; + } + + /** + * Runs `task` against browser storage although server mode is active. + * Only the migration export uses it, inside a modal flow. + */ + async runWithBrowserStorage(task: () => Promise): Promise { + this.browserOverrideDepth += 1; + try { + return await task(); + } finally { + this.browserOverrideDepth -= 1; + } + } kind(): PlaylistStorageKind { + if (this.serverStore && this.browserOverrideDepth === 0) { + return 'server'; + } return this.runtime.supportsSqlite ? 'electron' : 'indexeddb'; } /** The document store for `kind()`, or `null` for IndexedDB. */ documentStore(): PlaylistDocumentStore | null { - if (this.kind() !== 'electron' || typeof window === 'undefined') { + const kind = this.kind(); + if (kind === 'server') { + return this.serverStore; + } + if (kind !== 'electron' || typeof window === 'undefined') { return null; } return (window.electron as PlaylistDocumentStore | undefined) ?? null;