PrivatetimerPrivateinPrivateparamsLatest scheduleSave() arguments not yet written (null once written/cancelled).
PrivatefirstEpoch ms of the first scheduleSave() since the last write: the maxWait anchor.
PrivatelastEpoch ms the last index write started (null = none this session).
PrivateleadingEpoch ms the pending leading-edge save is due (null = no leading edge armed).
PrivatesaveA save came due while one was in flight; write once more when it settles.
Read and parse _cache_meta.json. Returns null on cold start
(file missing, or empty: a first save interrupted before close). On parse failure, returns a fresh snapshot with
needsOrphanCleanup = true and increments parseFailures —
caller should run cleanupOrphans to reclaim stray files.
Schedule a debounced metadata save.
Trailing debounce of delayMs, BOUNDED by maxWaitMs: a call re-arms the
timer (last writer wins), but never past maxWaitMs after the first
still-unsaved call. Without the ceiling a continuous write stream re-arms
the timer forever — measured in real playback: 65k save attempts and zero
index writes in 53 s, so an interrupted session left an index of ~40
entries for ~5,000 files on disk. When the timer fires, getSnapshot is
called to produce the latest state and the file is written; failures
invoke onError.
With leadingDelayMs, the first call after a quiet period (no write
started for delayMs) is written within that delay instead. The trailing
debounce alone lost a whole session's index to a reload landing inside it,
because a save started at unload never completes across a navigation
(measured on Chromium). A sustained burst still gets the trailing debounce
once the leading write has gone out.
Index writes never overlap: a save due while the previous one is still in
flight is deferred until it settles, and any number of such saves collapse
into ONE follow-up write of the then-latest snapshot (two concurrent
createWritable() streams on one file are not safe).
PrivateleadingWhen a leading-edge save is due for a first call at now, or null when none applies.
Start the scheduled save NOW instead of waiting for its timer. The
page-lifecycle hook (pagehide / visibilitychange → hidden): the page
may be frozen or killed right after the event, so the write is started
synchronously and not awaited. A no-op when nothing is scheduled.
PrivatefireRun (or, while a save is in flight, defer) the scheduled index write.
True if a debounced save is queued and has not yet fired.
Cancel the debounced timer without running its action. Caller is
responsible for any final synchronous save (typically only useful
during dispose, paired with a direct save() call).
Await any save started by the timer; no-op if none.
Synchronously write the snapshot to disk. Used by dispose for
the final flush; swallows + logs errors so dispose never throws.
Reclaim OPFS files that exist on disk but have no entry in the
provided expected set. Called from OPFSStore.init() after a
metadata-parse failure; safe to skip otherwise (the cache
rebuilds itself in seconds and orphans are bounded by quota).
Increments orphansRemoved per file actually deleted.
shouldStop is re-polled across the crawl's awaits; when it turns true
(the owning store was disposed) the crawl halts before its next delete,
so a stale expected-set can never keep reclaiming files a newer same-URL
store is concurrently writing.
OptionalshouldStop: () => boolean
Owns the OPFS metadata file (
_cache_meta.json) lifecycle: load + parse on init, debounced save on mutation, orphan cleanup when the file is corrupt, and the in-flight + pending-timer state that letsOPFSStore.dispose()flush cleanly.Counters (
parseFailures,orphansRemoved) are surfaced throughOPFSStore.getStats().