91 lines
2.2 KiB
TypeScript
91 lines
2.2 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { ref } from 'vue'
|
|
|
|
const cloneJson = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T
|
|
|
|
export const useKvStore = defineStore('kv', () => {
|
|
const entries = ref<Record<string, unknown>>({})
|
|
const ready = ref(false)
|
|
const loading = ref<Promise<void> | null>(null)
|
|
|
|
const ensureReady = async () => {
|
|
if (ready.value) return
|
|
if (loading.value) {
|
|
await loading.value
|
|
return
|
|
}
|
|
loading.value = (async () => {
|
|
ready.value = true
|
|
})()
|
|
await loading.value
|
|
loading.value = null
|
|
}
|
|
|
|
const getItem = async <T = unknown>(keyRaw: string | number): Promise<T | null> => {
|
|
await ensureReady()
|
|
const key = String(keyRaw || '').trim()
|
|
if (!key) return null
|
|
if (!Object.prototype.hasOwnProperty.call(entries.value, key)) return null
|
|
return cloneJson(entries.value[key] as T)
|
|
}
|
|
|
|
const setItem = async <T = unknown>(keyRaw: string | number, value: T): Promise<void> => {
|
|
await ensureReady()
|
|
const key = String(keyRaw || '').trim()
|
|
if (!key) return
|
|
entries.value[key] = cloneJson(value)
|
|
}
|
|
|
|
const removeItem = async (keyRaw: string | number): Promise<void> => {
|
|
await ensureReady()
|
|
const key = String(keyRaw || '').trim()
|
|
if (!key) return
|
|
delete entries.value[key]
|
|
}
|
|
|
|
const keys = async (): Promise<string[]> => {
|
|
await ensureReady()
|
|
return Object.keys(entries.value)
|
|
}
|
|
|
|
const clear = async (): Promise<void> => {
|
|
await ensureReady()
|
|
entries.value = {}
|
|
}
|
|
|
|
const exportEntries = async () => {
|
|
await ensureReady()
|
|
return Object.entries(entries.value).map(([key, value]) => ({ key, value: cloneJson(value) }))
|
|
}
|
|
|
|
const importEntries = async (
|
|
incoming: Array<{ key: string; value: unknown }>,
|
|
options?: { replace?: boolean }
|
|
) => {
|
|
await ensureReady()
|
|
if (options?.replace !== false) {
|
|
entries.value = {}
|
|
}
|
|
for (const item of incoming || []) {
|
|
const key = String(item?.key || '').trim()
|
|
if (!key) continue
|
|
entries.value[key] = cloneJson(item.value)
|
|
}
|
|
}
|
|
|
|
return {
|
|
entries,
|
|
ready,
|
|
ensureReady,
|
|
getItem,
|
|
setItem,
|
|
removeItem,
|
|
keys,
|
|
clear,
|
|
exportEntries,
|
|
importEntries
|
|
}
|
|
}, {
|
|
persist: true
|
|
})
|