Skip to content
Clone
93a2be6
45 lines 1.4 KB
/**
* Persistence driver contract for the local-first cache.
*
* One envelope shape travels through every layer (memory, IndexedDB,
* localStorage), so a value written by one driver stays readable after the
* page degrades to another: `v` guards against envelope changes between
* builds, `at` powers the prefetch throttle window.
*/
export const ENVELOPE_VERSION = 1
export interface CacheEnvelope<T = unknown> {
/** Envelope schema version — entries from other versions are discarded. */
v: number
/** Write timestamp in ms, used for prefetch freshness checks. */
at: number
data: T
}
export interface KVDriver {
readonly name: 'indexeddb' | 'localstorage' | 'memory'
get(key: string): Promise<CacheEnvelope | undefined>
set(key: string, value: CacheEnvelope): Promise<void>
del(key: string): Promise<void>
/** Remove every key starting with `prefix`; `''` wipes the whole store. */
clearPrefix(prefix: string): Promise<void>
/** Real write-read-delete roundtrip; rejects when the backend is unusable. */
probe(): Promise<void>
}
export function withTimeout<T>(promise: Promise<T>, ms: number, reason: string): Promise<T> {
return new Promise<T>((resolve, reject) => {
const timer = setTimeout(() => reject(new Error(reason)), ms)
promise.then(
(value) => {
clearTimeout(timer)
resolve(value)
},
(err) => {
clearTimeout(timer)
reject(err)
},
)
})
}