import type { KVSSync , KVSSyncOptions , StoreNames , StoreValue } from "@kvs/types" ; import { JsonValue } from "./JSONValue" ; export type KVSStorageKey = string ; export const getItem = < Schema extends StorageSchema > ( storage , key ) => { const item = storage . getItem ( String ( key ) ) ; return item !== null ? JSON . parse ( item ) : undefined ; } ; export const hasItem = < Schema extends StorageSchema > ( storage , key ) => { return storage . getItem ( String ( key ) ) !== null ; } ; export const setItem = < Schema extends StorageSchema > ( storage , key , value ) => { if ( value === undefined ) { return deleteItem ( storage , key ) ; } return storage . setItem ( String ( key ) , JSON . stringify ( value ) ) ; } ; export const clearItem = ( storage , kvsVersionKey , options ) => { const currentVersion = getItem < any > ( storage , kvsVersionKey ) ; storage . clear ( ) ; if ( options . force ) { return ; } if ( currentVersion !== undefined ) { setItem < any > ( storage , kvsVersionKey , currentVersion ) ; } } ; export const deleteItem = < Schema extends StorageSchema > ( storage , key ) : boolean => { try { storage . removeItem ( String ( key ) ) ; return true ; } catch { return false ; } } ; export function * createIterator < Schema extends StorageSchema > ( storage , kvsVersionKey ) { for ( let i = 0 ; i < storage . length ; i ++ ) { const key = storage . key ( i ) as StoreNames < Schema > | undefined ; if ( ! key ) { continue ; } if ( key === kvsVersionKey ) { continue ; } const value = getItem ( storage , key ) ; yield [ key , value ] ; } } const DEFAULT_KVS_VERSION = 1 ; const openStorage = ( { storage , version , kvsVersionKey , onUpgrade } ) => { let oldVersion = getItem < any > ( storage , kvsVersionKey ) ; if ( oldVersion === undefined ) { setItem < any > ( storage , kvsVersionKey , DEFAULT_KVS_VERSION ) ; oldVersion = 0 ; } if ( oldVersion !== version ) { onUpgrade ( { oldVersion , newVersion : version , storage } ) ; return storage ; } return storage ; } ; const createStore = < Schema extends StorageSchema > ( { storage , kvsVersionKey } ) : KvsStorageSync < Schema > => { const store = { get < K extends StoreNames < Schema > > ( key ) { return getItem < Schema > ( storage , key ) ; } , has ( key ) { return hasItem < Schema > ( storage , key ) ; } , set < K extends StoreNames < Schema > > ( key , value ) { setItem < Schema > ( storage , key , value ) ; return store ; } , clear ( ) { return clearItem ( storage , kvsVersionKey , { force : false } ) ; } , delete ( key ) { return deleteItem < Schema > ( storage , key ) ; } , dropInstance ( ) { return clearItem ( storage , kvsVersionKey , { force : true } ) ; } , close ( ) { return ; } , [ Symbol . iterator ] ( ) { const iterator = createIterator < Schema > ( storage , kvsVersionKey ) ; return { next ( ) { return iterator . next ( ) ; } } ; } } ; return store ; } ; export type StorageSchema = { [ index ] : JsonValue ; } ; export type KvsStorageSync < Schema extends StorageSchema > = KVSSync < Schema > ; export type KvsStorageSyncOptions < Schema extends StorageSchema > = KVSSyncOptions < Schema > & { kvsVersionKey ? : string ; storage : Storage ; } ; export const kvsStorageSync = < Schema extends StorageSchema > ( options ) : KvsStorageSync < Schema > => { const { name , version , upgrade , ... kvStorageOptions } = options ; const kvsVersionKey = kvStorageOptions . kvsVersionKey ?? "__kvs_version__" ; const storage = openStorage ( { storage : options . storage , version : options . version , onUpgrade : ( { oldVersion , newVersion , storage } ) => { if ( ! options . upgrade ) { return ; } return options . upgrade ( { kvs : createStore ( { storage , kvsVersionKey } ) , oldVersion , newVersion } ) ; } , kvsVersionKey } ) ; return createStore ( { storage , kvsVersionKey } ) ; } ;