I'm using zustand with persist plugin to store the state of my application. I want to use localstorage but the cache has to be encrypted.
For encryption, I'm using encrypt-storage. For encryption keys, I want to make an API call to the backend and initialise the encrypt storage.
The problem is while the API call is being made, the storage is still undefined. How to properly initialise zustand with encrypt-storage ?
Here is what I have tried :
import { EncryptStorage } from "encrypt-storage";
import { create } from "zustand";
import { devtools, persist, } from "zustand/middleware";
import { createJSONStorage } from "zustand/middleware"
const fake_api = (ms: number) => new Promise(resolve => {
setTimeout(resolve, ms)
})
export function KeyResolver(callback: () => void) {
const fn = async () => {
//
await fake_api(2000);
console.log("encryption key retrieved")
encryptStorage.EKEY = 'secret-key-value';
encryptStorage.storage = new EncryptStorage(encryptStorage.EKEY, {
stateManagementUse: true,
});
callback();
};
if (!encryptStorage.EKEY) {
fn();
}
}
interface IEncryptStorage {
storage: undefined | EncryptStorage,
EKEY: null | string,
}
export const encryptStorage: IEncryptStorage = {
storage: undefined,
EKEY: null,
}
const useOptimiserStore = create<IOptimiserStore>()(
devtools(
persist(
(set) => ({
...initialOtimiserStoreState,
_hasHydrated: false,
setHyderated: (val) => set({ _hasHydrated: val })
}),
{
name: "optimiser-storage",
// @ts-expect-error
storage: createJSONStorage(() => encryptStorage.storage),
onRehydrateStorage: () => {
KeyResolver(() => {
useOptimiserStore.getState().setHyderated(true)
});
}
}
),
{
name: "optimiser-storage",
}
)
);
// And i'm using it inside my component like this:
const Component = () => {
const hasHyderated = useOptimiserStore(state => state._hasHydrated);
if (!hasHyderated) {
return <>retreiving encryption keys </>
}
return <div> ... </div>
}
But I get the following error:
Uncaught TypeError: can't access property "setItem", storage is undefined