UNPKG

@renegade-fi/core

Version:
92 lines (82 loc) 2.88 kB
import type { PartializedState } from './createConfig.js' import type { Evaluate } from './types/utils.js' import { deserialize as deserialize_ } from './utils/deserialize.js' import { serialize as serialize_ } from './utils/serialize.js' // key-values for loose autocomplete and typing export type StorageItemMap = { recentConnectorId: string state: PartializedState } export type Storage< itemMap extends Record<string, unknown> = Record<string, unknown>, /// storageItemMap extends StorageItemMap = StorageItemMap & itemMap, > = { key: string getItem< key extends keyof storageItemMap, value extends storageItemMap[key], defaultValue extends value | null | undefined, >( key: key, defaultValue?: defaultValue | undefined, ): | (defaultValue extends null ? value | null : value) | Promise<defaultValue extends null ? value | null : value> setItem< key extends keyof storageItemMap, value extends storageItemMap[key] | null, >(key: key, value: value): void | Promise<void> removeItem(key: keyof storageItemMap): void | Promise<void> } export type BaseStorage = { getItem( key: string, ): string | null | undefined | Promise<string | null | undefined> setItem(key: string, value: string): void | Promise<void> removeItem(key: string): void | Promise<void> } export type CreateStorageParameters = { deserialize?: (<T>(value: string) => T) | undefined key?: string | undefined serialize?: (<T>(value: T) => string) | undefined storage?: Evaluate<BaseStorage> | undefined } export function createStorage< itemMap extends Record<string, unknown> = Record<string, unknown>, storageItemMap extends StorageItemMap = StorageItemMap & itemMap, >(parameters: CreateStorageParameters): Evaluate<Storage<storageItemMap>> { const { deserialize = deserialize_, key: prefix = 'trade.renegade', serialize = serialize_, storage = noopStorage, } = parameters function unwrap<type>(value: type): type | Promise<type> { if (value instanceof Promise) return value.then((x) => x).catch(() => null) return value } return { ...storage, key: prefix, async getItem(key, defaultValue) { const value = storage.getItem(`${prefix}.${key as string}`) const unwrapped = await unwrap(value) if (unwrapped) return deserialize(unwrapped) ?? null return (defaultValue ?? null) as any }, async setItem(key, value) { const storageKey = `${prefix}.${key as string}` if (value === null) await unwrap(storage.removeItem(storageKey)) else await unwrap(storage.setItem(storageKey, serialize(value))) }, async removeItem(key) { await unwrap(storage.removeItem(`${prefix}.${key as string}`)) }, } } export const noopStorage = { getItem: () => null, setItem: () => {}, removeItem: () => {}, } satisfies BaseStorage