Removal of localStorage dependency v1

This commit is contained in:
viniersiren
2025-07-09 11:55:42 -07:00
parent 41fe5f4cb0
commit bf587d58c7
5 changed files with 122 additions and 35 deletions
+56 -10
View File
@@ -9,6 +9,7 @@ import {
deriveIsDeleted,
getter,
synced,
localStorageProvider,
throttled,
withGetter,
} from "../src/index"
@@ -40,24 +41,52 @@ describe("Store utilities", () => {
})
describe("synced", () => {
it("should sync with localStorage", () => {
const store = synced("testKey", "default")
it("should sync with localStorage", async () => {
const store = synced({
key: "testKey",
storage: localStorageProvider,
defaultValue: "default",
})
// Wait for async initialization using vi.runAllTimersAsync
await vi.runAllTimersAsync()
expect(get(store)).toBe("default")
store.set("new value")
// Wait for async save using vi.runAllTimersAsync
await vi.runAllTimersAsync()
expect(localStorage.getItem("testKey")).toBe(JSON.stringify("new value"))
})
it("should load existing value from localStorage", () => {
it("should load existing value from localStorage", async () => {
localStorage.setItem("testKey", JSON.stringify("existing"))
const store = synced("testKey", "default")
const store = synced({
key: "testKey",
storage: localStorageProvider,
defaultValue: "default",
})
// Wait for async initialization using vi.runAllTimersAsync
await vi.runAllTimersAsync()
expect(get(store)).toBe("existing")
})
})
describe("getter", () => {
it("should return current store value", () => {
const store = synced("test", "initial")
it("should return current store value", async () => {
const store = synced({
key: "test",
storage: localStorageProvider,
defaultValue: "initial",
})
// Wait for async initialization using vi.runAllTimersAsync
await vi.runAllTimersAsync()
const getValue = getter(store)
expect(getValue()).toBe("initial")
@@ -67,8 +96,17 @@ describe("Store utilities", () => {
})
describe("withGetter", () => {
it("should add getter to writable store", () => {
const store = withGetter(synced("test", "initial"))
it("should add getter to writable store", async () => {
const store = withGetter(
synced({
key: "test",
storage: localStorageProvider,
defaultValue: "initial",
}),
)
// Wait for async initialization using vi.runAllTimersAsync
await vi.runAllTimersAsync()
expect(store.get()).toBe("initial")
store.set("updated")
@@ -77,9 +115,17 @@ describe("Store utilities", () => {
})
describe("throttled", () => {
it("should throttle updates", () => {
it("should throttle updates", async () => {
const mockFn = vi.fn()
const store = synced("test", 0)
const store = synced({
key: "test",
storage: localStorageProvider,
defaultValue: 0,
})
// Wait for async initialization using vi.runAllTimersAsync
await vi.runAllTimersAsync()
const throttledStore = throttled(100, store)
throttledStore.subscribe(mockFn)
+30 -4
View File
@@ -1,11 +1,37 @@
import {writable} from "svelte/store"
import {getJson, setJson} from "@welshman/lib"
export const synced = <T>(key: string, defaultValue: T) => {
const init = getJson(key)
const store = writable<T>(init === undefined ? defaultValue : init)
export interface StorageProvider {
get: (key: string) => Promise<any>
set: (key: string, value: any) => Promise<void>
}
store.subscribe((value: T) => setJson(key, value))
export interface SyncedConfig {
key: string
storage: StorageProvider
defaultValue: any
}
export const localStorageProvider: StorageProvider = {
get: async (key: string) => getJson(key),
set: async (key: string, value: any) => setJson(key, value),
}
export const synced = <T>(config: SyncedConfig) => {
const {key, storage, defaultValue} = config
const store = writable<T>(defaultValue)
// Async initialization
storage.get(key).then((value: any) => {
if (value !== undefined) {
store.set(value)
}
})
// Subscribe to changes
store.subscribe(async (value: T) => {
await storage.set(key, value)
})
return store
}