import { clear, createStore, del, entries, get, keys, set, setMany, } from 'idb-keyval'; export type ConfigStore = { get: (key: string) => Promise; set: (key: string, value: T) => Promise; setMany: (values: [string, T][]) => Promise; keys: () => Promise; entries: () => Promise<[string, T][]>; delete: (key: string) => Promise; clear: () => Promise; }; const initialIndexedDB = (database: string): ConfigStore => { const store = createStore(`affine:${database}`, 'database'); return { get: (key: string) => get(key, store), set: (key: string, value: T) => set(key, value, store), setMany: (values: [string, T][]) => setMany(values, store), keys: () => keys(store), entries: () => entries(store), delete: (key: string) => del(key, store), clear: () => clear(store), }; }; const scopedIndexedDB = () => { const idb = initialIndexedDB('global'); const storeCache = new Map>(); return (scope: string): Readonly> => { if (!storeCache.has(scope)) { const prefix = `${scope}:`; const store = { get: async (key: string) => idb.get(prefix + key), set: (key: string, value: T) => idb.set(prefix + key, value), setMany: (values: [string, T][]) => idb.setMany(values.map(([k, v]) => [`${scope}:${k}`, v])), keys: () => idb .keys() .then(keys => keys .filter(k => k.startsWith(prefix)) .map(k => k.slice(prefix.length)) ), entries: () => idb .entries() .then(entries => entries .filter(([k]) => k.startsWith(prefix)) .map(([k, v]) => [k.slice(prefix.length), v] as [string, T]) ), delete: (key: string) => idb.delete(prefix + key), clear: async () => { await idb .keys() .then(keys => Promise.all( keys.filter(k => k.startsWith(prefix)).map(k => del(k)) ) ); }, }; storeCache.set(scope, store); } return storeCache.get(scope) as ConfigStore; }; }; let lazyKVConfigure: ReturnType | undefined = undefined; export const getKVConfigure = (scope: string) => { if (!lazyKVConfigure) { lazyKVConfigure = scopedIndexedDB(); } return lazyKVConfigure(scope); };