import { vaultStorage } from "./storage.js"; import { createRuntime } from "./runtime.js"; /** * @typedef {import("./storage.js").StoredWallet} StoredWallet * @typedef {import("./storage.js").AddWalletInput} AddWalletInput * @typedef {ReturnType} WalletRuntime */ export function createVault() { /** @type {StoredWallet[]} */ let wallets = []; let selectedId = ""; let locked = hasVault(); let password = ""; let ephemeral = false; /** @type {Map} */ const runtimes = new Map(); function hasVault() { return vaultStorage.has(); } function syncSelected() { selectedId = wallets.some((wallet) => wallet.id === selectedId) ? selectedId : wallets[0]?.id ?? ""; } function clear() { wallets = []; selectedId = ""; runtimes.clear(); } /** * @returns {StoredWallet | undefined} */ function selectedWallet() { return wallets.find((wallet) => wallet.id === selectedId); } /** * @returns {{ wallet: StoredWallet, runtime: WalletRuntime } | undefined} */ function current() { const wallet = selectedWallet(); const runtime = wallet ? runtimes.get(wallet.id) : undefined; return wallet && runtime ? { wallet, runtime } : undefined; } /** * @param {StoredWallet} wallet * @param {WalletRuntime} runtime */ function isCurrent(wallet, runtime) { return runtimes.get(wallet.id) === runtime; } /** * @param {string} walletId */ function select(walletId) { selectedId = walletId; syncSelected(); } function lock() { clear(); password = ""; ephemeral = false; locked = hasVault(); } function reset() { vaultStorage.reset(); clear(); password = ""; ephemeral = false; locked = false; } function startEphemeral() { clear(); password = ""; ephemeral = true; locked = false; } function clearEphemeral() { clear(); password = ""; ephemeral = false; locked = hasVault(); } /** * @param {string} pagePassword */ async function setup(pagePassword) { await vaultStorage.setup(pagePassword); clear(); password = pagePassword; ephemeral = false; locked = false; } /** * @param {string} pagePassword */ async function unlock(pagePassword) { wallets = await vaultStorage.load(pagePassword); syncSelected(); runtimes.clear(); password = pagePassword; ephemeral = false; locked = false; for (const wallet of wallets) { runtimes.set(wallet.id, createRuntime(wallet.source)); } } /** * @param {AddWalletInput} input */ async function addWallet(input) { if (ephemeral) { const wallet = vaultStorage.createWallet(input); wallets = [...wallets, wallet]; selectedId = wallet.id; locked = false; runtimes.set(wallet.id, createRuntime(wallet.source)); return; } const added = await vaultStorage.addWallet(wallets, input, password); wallets = added.wallets; selectedId = added.wallet.id; locked = false; runtimes.set(added.wallet.id, createRuntime(added.wallet.source)); } /** * @param {string} walletId */ async function deleteWallet(walletId) { if (ephemeral) { wallets = wallets.filter((wallet) => wallet.id !== walletId); } else { wallets = await vaultStorage.deleteWallet(wallets, walletId, password); } runtimes.delete(walletId); syncSelected(); } return { get wallets() { return wallets; }, get selectedId() { return selectedId; }, get hasPassword() { return password !== ""; }, needsSetup() { return !hasVault() && !password && !ephemeral; }, isLocked() { return !ephemeral && locked && hasVault(); }, isEphemeral() { return ephemeral; }, current, isCurrent, select, lock, reset, startEphemeral, clearEphemeral, setup, unlock, addWallet, deleteWallet, }; }