dgb-wallet/packages/keystore/src/storage.ts
Digibyte.X d50286a9a5 DigiByte.X Wallet — recovery-first web wallet monorepo
Packages: core (BIP39/32/44/49/84/86 derivation, WIF), keystore (PBKDF2 +
AES-GCM), psbt, p2p (BIP157/158 SPV daemon, Dandelion++ broadcast with
relay-echo verification), blockbook, rpc, electrum, net, bns, web-ui
(React/Vite), mobile (Expo). ops/ holds the nginx vhost, systemd unit and
push.sh deploy script for digibyte.x/web.
2026-09-20 20:16:52 +02:00

51 lines
2.3 KiB
TypeScript

// Storage adapter — an intentionally tiny surface so we can plug in
// whatever the host platform gives us for at-rest bytes:
// - browser → LocalStorageAdapter (uses window.localStorage)
// - RN → SecureStoreAdapter (expo-secure-store, wired later)
// - Node/CLI → NodeFsAdapter (writes JSON files under a dir)
// - tests → InMemoryAdapter (Map-backed)
//
// The keystore itself doesn't care which one it got — it just persists
// EncryptedBlob JSON strings keyed by user-chosen label.
export interface StorageAdapter {
readonly name: string;
get(key: string): Promise<string | null>;
put(key: string, value: string): Promise<void>;
delete(key: string): Promise<void>;
list(prefix?: string): Promise<string[]>;
}
// Pure in-memory adapter, for tests and CLIs that don't want to touch
// disk. Also useful as a default when a platform adapter isn't ready.
export class InMemoryAdapter implements StorageAdapter {
readonly name = 'memory';
private readonly map = new Map<string, string>();
async get(key: string): Promise<string | null> { return this.map.get(key) ?? null; }
async put(key: string, value: string): Promise<void> { this.map.set(key, value); }
async delete(key: string): Promise<void> { this.map.delete(key); }
async list(prefix = ''): Promise<string[]> {
return [...this.map.keys()].filter((k) => k.startsWith(prefix));
}
}
// Browser adapter over window.localStorage. Synchronous under the hood
// but we present the async interface so consumers can swap in a real
// async backend (IndexedDB, expo-secure-store) without rewrites.
export class LocalStorageAdapter implements StorageAdapter {
readonly name = 'localStorage';
constructor(private readonly ls: Storage = globalThis.localStorage) {
if (!this.ls) throw new Error('LocalStorageAdapter: no localStorage available in this environment');
}
async get(key: string): Promise<string | null> { return this.ls.getItem(key); }
async put(key: string, value: string): Promise<void> { this.ls.setItem(key, value); }
async delete(key: string): Promise<void> { this.ls.removeItem(key); }
async list(prefix = ''): Promise<string[]> {
const out: string[] = [];
for (let i = 0; i < this.ls.length; i++) {
const k = this.ls.key(i);
if (k && k.startsWith(prefix)) out.push(k);
}
return out;
}
}