import { create } from "zustand"; import { combine, persist, createJSONStorage } from "zustand/middleware"; import { Updater } from "../typing"; import { deepClone } from "./clone"; import { indexedDBStorage } from "@/app/utils/indexedDB-storage"; type SecondParam = T extends ( _f: infer _F, _s: infer S, ...args: infer _U ) => any ? S : never; type MakeUpdater = { lastUpdateTime: number; _hasHydrated: boolean; markUpdate: () => void; update: Updater; setHasHydrated: (state: boolean) => void; }; type SetStoreState = ( partial: T | Partial | ((state: T) => T | Partial), replace?: boolean | undefined, ) => void; export function createPersistStore( state: T, methods: ( set: SetStoreState>, get: () => T & MakeUpdater, ) => M, persistOptions: SecondParam>>, ) { persistOptions.storage = createJSONStorage(() => indexedDBStorage); const oldOonRehydrateStorage = persistOptions?.onRehydrateStorage; persistOptions.onRehydrateStorage = (state) => { oldOonRehydrateStorage?.(state); return () => state.setHasHydrated(true); }; return create( persist( combine( { ...state, lastUpdateTime: 0, _hasHydrated: false, }, (set, get) => { return { ...methods(set, get as any), markUpdate() { set({ lastUpdateTime: Date.now() } as Partial< T & M & MakeUpdater >); }, update(updater) { const state = deepClone(get()); updater(state); set({ ...state, lastUpdateTime: Date.now(), }); }, setHasHydrated: (state: boolean) => { set({ _hasHydrated: state } as Partial>); }, } as M & MakeUpdater; }, ), persistOptions as any, ), ); }