[Drafts] Storage fixes (#9790)
* delete media from existsCache when deleting * revoke media URLs * skip revoking objecturls until the composer is completely closed * [Drafts] Metrics (#9794) * metrics for drafts * Nit: format * nit: use new util for clarity * nit: use new util for clarity --------- Co-authored-by: Eric Bailey <git@esb.lol> --------- Co-authored-by: Eric Bailey <git@esb.lol>
This commit is contained in:
@@ -356,6 +356,7 @@ export function draftViewToSummary(
|
||||
hasMissingMedia,
|
||||
mediaCount,
|
||||
postCount: view.draft.posts.length,
|
||||
createdAt: view.createdAt,
|
||||
updatedAt: view.updatedAt,
|
||||
posts,
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ export type DraftSummary = {
|
||||
mediaCount: number
|
||||
/** Number of posts in thread */
|
||||
postCount: number
|
||||
/** ISO timestamp of creation */
|
||||
createdAt: string
|
||||
/** ISO timestamp of last update */
|
||||
updatedAt: string
|
||||
/** All posts in the draft for full display */
|
||||
|
||||
@@ -91,6 +91,7 @@ export async function deleteMediaFromLocal(
|
||||
if (file.exists) {
|
||||
file.delete()
|
||||
}
|
||||
mediaExistsCache.delete(localRefPath)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,3 +155,17 @@ export function clearMediaCache(): void {
|
||||
cachePopulated = false
|
||||
populateCachePromise = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke a media URL (no-op on native - only needed for web blob URLs)
|
||||
*/
|
||||
export function revokeMediaUrl(_url: string): void {
|
||||
// No-op on native - file URIs don't need revocation
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke all media URLs (no-op on native - only needed for web blob URLs)
|
||||
*/
|
||||
export function revokeAllMediaUrls(): void {
|
||||
// No-op on native - file URIs don't need revocation
|
||||
}
|
||||
|
||||
@@ -84,6 +84,11 @@ export async function saveMediaToLocal(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Track blob URLs created by loadMediaFromLocal for cleanup
|
||||
*/
|
||||
const createdBlobUrls = new Set<string>()
|
||||
|
||||
/**
|
||||
* Load a media file from IndexedDB
|
||||
* @returns A blob URL for the saved media
|
||||
@@ -97,7 +102,10 @@ export async function loadMediaFromLocal(
|
||||
throw new Error(`Media file not found: ${localRefPath}`)
|
||||
}
|
||||
|
||||
return URL.createObjectURL(record.blob)
|
||||
const url = URL.createObjectURL(record.blob)
|
||||
logger.debug('Created blob URL', {url})
|
||||
createdBlobUrls.add(url)
|
||||
return url
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,6 +173,20 @@ export function clearMediaCache(): void {
|
||||
*/
|
||||
export function revokeMediaUrl(url: string): void {
|
||||
if (url.startsWith('blob:')) {
|
||||
logger.debug('Revoking blob URL', {url})
|
||||
URL.revokeObjectURL(url)
|
||||
createdBlobUrls.delete(url)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke all blob URLs created by loadMediaFromLocal.
|
||||
* Call this when closing the drafts list dialog to prevent memory leaks.
|
||||
*/
|
||||
export function revokeAllMediaUrls(): void {
|
||||
logger.debug(`Revoking ${createdBlobUrls.size} blob URLs`)
|
||||
for (const url of createdBlobUrls) {
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
createdBlobUrls.clear()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user