From 28da42fd61ee1b8616edcd438b45007d0586be3d Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 16 Jan 2026 11:30:28 +0200 Subject: [PATCH] fix: ensure media cache is populated before checking exists On iOS (and web), the media cache wasn't populated before the drafts query ran, causing drafts with local media to incorrectly show as "missing media" on app restart. The issue would resolve itself after closing and reopening the composer because by then the cache was ready. This fix adds ensureMediaCachePopulated() and awaits it in useDrafts before checking which media exists locally. Co-Authored-By: Claude Opus 4.5 --- src/state/drafts/hooks.ts | 2 ++ src/state/drafts/storage.web.ts | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/state/drafts/hooks.ts b/src/state/drafts/hooks.ts index cb6df2afd5..e0c02131bb 100644 --- a/src/state/drafts/hooks.ts +++ b/src/state/drafts/hooks.ts @@ -25,6 +25,8 @@ export function useDrafts() { return useQuery({ queryKey: DRAFTS_QUERY_KEY, queryFn: async () => { + // Ensure media cache is populated before checking which media exists + await storage.ensureMediaCachePopulated() const res = await agent.app.bsky.draft.getDrafts({}) return res.data.drafts.map(view => draftViewToSummary(view, path => storage.mediaExists(path)), diff --git a/src/state/drafts/storage.web.ts b/src/state/drafts/storage.web.ts index dc85640d6b..d7377fe51c 100644 --- a/src/state/drafts/storage.web.ts +++ b/src/state/drafts/storage.web.ts @@ -137,19 +137,20 @@ export async function deleteMediaFromLocal( */ const mediaExistsCache = new Map() let cachePopulated = false +let populateCachePromise: Promise | null = null export function mediaExists(localRefPath: string): boolean { if (mediaExistsCache.has(localRefPath)) { return mediaExistsCache.get(localRefPath)! } // If cache not populated yet, trigger async population - if (!cachePopulated) { - populateCache() + if (!cachePopulated && !populateCachePromise) { + populateCachePromise = populateCacheInternal() } return false // Conservative: assume doesn't exist if not in cache } -async function populateCache(): Promise { +async function populateCacheInternal(): Promise { try { const db = await getDB() const keys = await db.getAllKeys('media') @@ -162,12 +163,24 @@ async function populateCache(): Promise { } } +/** + * Ensure the media cache is populated. Call this before checking mediaExists. + */ +export async function ensureMediaCachePopulated(): Promise { + if (cachePopulated) return + if (!populateCachePromise) { + populateCachePromise = populateCacheInternal() + } + await populateCachePromise +} + /** * Clear the media exists cache (call when media is added/deleted) */ export function clearMediaCache(): void { mediaExistsCache.clear() cachePopulated = false + populateCachePromise = null } /**