accounts
Version:
Tempo Accounts SDK
85 lines • 3.27 kB
JavaScript
import { persist } from 'zustand/middleware';
import { subscribeWithSelector } from 'zustand/middleware';
import { createStore } from 'zustand/vanilla';
import * as Storage from './Storage.js';
/**
* Creates a Zustand vanilla store with `subscribeWithSelector` and `persist` middleware.
*/
export function create(options) {
const { chainId, maxAccounts, persistCredentials = true, storage = typeof window !== 'undefined'
? Storage.idb({ key: 'tempo' })
: Storage.memory({ key: 'tempo' }), } = options;
return createStore(subscribeWithSelector(persist(() => ({
accessKeys: [],
accounts: [],
activeAccount: 0,
chainId,
requestQueue: [],
}), {
merge: hydrate,
name: 'store',
partialize: (state) => serialize(state, { maxAccounts, persistCredentials }),
storage,
version: 0,
})));
}
/** Converts runtime provider state into the persisted refresh snapshot. */
export function serialize(state, options = {}) {
const { maxAccounts, persistCredentials = true } = options;
const accounts = maxAccounts && state.accounts.length > maxAccounts
? state.accounts.slice(0, maxAccounts)
: state.accounts;
return {
accounts,
activeAccount: state.activeAccount,
...(persistCredentials ? { accessKeys: state.accessKeys } : {}),
...(state.auth ? { auth: state.auth } : {}),
chainId: state.chainId,
};
}
/** Restores runtime provider state from a persisted refresh snapshot. */
export function hydrate(persisted, current) {
const state = persisted && typeof persisted === 'object' ? persisted : {};
return {
...state,
...current,
// Preserve in-memory credentials when persisted accounts only have addresses.
accounts: state.accounts?.map((persisted) => {
const account = current.accounts.find((a) => a.address.toLowerCase() === persisted.address.toLowerCase());
return account ?? persisted;
}) ?? current.accounts,
accessKeys: normalizeAccessKeys(state.accessKeys) ?? current.accessKeys,
chainId: state.chainId ?? current.chainId,
};
}
function normalizeAccessKeys(accessKeys) {
if (!accessKeys)
return undefined;
return accessKeys.filter((key) => {
if (!key || typeof key !== 'object')
return false;
const value = key;
return (typeof value.access === 'string' &&
typeof value.address === 'string' &&
typeof value.chainId === 'number' &&
(value.keyType === 'secp256k1' ||
value.keyType === 'p256' ||
value.keyType === 'webAuthn' ||
value.keyType === 'webCrypto'));
});
}
/**
* Waits for the store to finish hydrating from storage.
*
* Returns immediately if the store has already hydrated. Otherwise, waits
* for the `onFinishHydration` callback with a 100ms safety timeout fallback.
*/
export async function waitForHydration(store) {
if (store.persist.hasHydrated())
return;
await new Promise((resolve) => {
store.persist.onFinishHydration(() => resolve());
setTimeout(() => resolve(), 100);
});
}
//# sourceMappingURL=Store.js.map