]> git.codecow.com Git - libnemo.git/commitdiff
Deprecate NamedData type which is redundant against the built-in Record type. Clear...
authorChris Duncan <chris@zoso.dev>
Mon, 13 Oct 2025 08:18:16 +0000 (01:18 -0700)
committerChris Duncan <chris@zoso.dev>
Mon, 13 Oct 2025 08:18:16 +0000 (01:18 -0700)
12 files changed:
src/lib/database.ts
src/lib/rolodex.ts
src/lib/vault/index.ts
src/lib/vault/vault-worker.ts
src/lib/wallet/backup.ts
src/lib/wallet/create.ts
src/lib/wallet/get.ts
src/lib/wallet/index.ts
src/lib/wallet/load.ts
src/lib/wallet/unlock.ts
src/lib/wallet/update.ts
src/types.d.ts [deleted file]

index b6a7ef410020835589bb440698be47043231d3f1..a365c83911c14e5084eb90ebca2001dcf09e7702 100644 (file)
@@ -1,7 +1,7 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { Data, NamedData } from '#types'
+export type Data = boolean | number | number[] | string | string[] | ArrayBuffer | CryptoKey
 
 /**
 * Encrypts and stores data in the browser using IndexedDB.
@@ -20,11 +20,11 @@ export class Database {
        /**
        * Inserts records in a datastore, throwing if they already exist.
        *
-       * @param {NamedData} data - Object of key-value pairs
+       * @param {Record<string, Data | Record<string, Data>>} data - Object of key-value pairs
        * @param {string} store - Datastore in which to put records
        * @returns {Promise<(IDBValidKey | DOMException)[]>} Index keys of the records inserted
        */
-       static async add<T extends Data> (data: NamedData<T>, store: string): Promise<(IDBValidKey | DOMException)[]> {
+       static async add<T extends Data | Record<string, Data>> (data: Record<string, T>, store: string): Promise<(IDBValidKey | DOMException)[]> {
                this.#storage ??= await this.#open(this.DB_NAME)
                const transaction = this.#storage.transaction(store, 'readwrite')
                const db = transaction.objectStore(store)
@@ -88,18 +88,18 @@ export class Database {
        *
        * @param {string} name - Index key of the record to get
        * @param {string} store - Datastore from which to get the record
-       * @returns {Promise<NamedData>} Object of key-value pairs
+       * @returns {Promise<Record<string, Data | Record<string, Data>>>} Object of key-value pairs
        */
-       static async get<T extends Data> (id: string, store: string): Promise<NamedData<T>>
+       static async get<T extends Data | Record<string, Data>> (id: string, store: string): Promise<Record<string, T>>
        /**
        * Gets specific records from a datastore.
        *
        * @param {string[]} names - Index keys of the records to get
        * @param {string} store - Datastore from which to get records
-       * @returns {Promise<NamedData>} Object of key-value pairs
+       * @returns {Promise<Record<string, Data | Record<string, Data>>>} Object of key-value pairs
        */
-       static async get<T extends Data> (ids: string[], store: string): Promise<NamedData<T>>
-       static async get<T extends Data> (ids: string | string[], store: string): Promise<NamedData<T>> {
+       static async get<T extends Data | Record<string, Data>> (ids: string[], store: string): Promise<Record<string, T>>
+       static async get<T extends Data | Record<string, Data>> (ids: string | string[], store: string): Promise<Record<string, T>> {
                if (!Array.isArray(ids)) ids = [ids]
                this.#storage ??= await this.#open(this.DB_NAME)
                const transaction = this.#storage.transaction(store, 'readonly')
@@ -107,7 +107,7 @@ export class Database {
                return new Promise((resolve, reject) => {
                        const requests = ids.map(id => db.get(id))
                        transaction.oncomplete = (event) => {
-                               const results: NamedData<T> = {}
+                               const results: Record<string, T> = {}
                                for (const request of requests) {
                                        if (request?.result?.id != null) {
                                                results[request.result.id] = request.error ?? request.result
@@ -125,9 +125,9 @@ export class Database {
        * Gets all records from a specific datastore.
        *
        * @param {string} store - Datastore from which to get records
-       * @returns {Promise<NamedData>} Object of key-value pairs
+       * @returns {Promise<Record<string, Data | Record<string, Data>>>} Object of key-value pairs
        */
-       static async getAll<T extends Data> (store: string): Promise<NamedData<T>> {
+       static async getAll<T extends Data | Record<string, Data>> (store: string): Promise<Record<string, T>> {
                this.#storage ??= await this.#open(this.DB_NAME)
                const transaction = this.#storage.transaction(store, 'readonly')
                const db = transaction.objectStore(store)
@@ -139,7 +139,7 @@ export class Database {
                                } else if (request.result == null) {
                                        reject('getAll request failed')
                                } else {
-                                       const results: NamedData<T> = {}
+                                       const results: Record<string, T> = {}
                                        for (const result of request.result) {
                                                results[result.id] = request.error ?? result
                                        }
@@ -155,11 +155,11 @@ export class Database {
        /**
        * Inserts records in a datastore, overwriting existing data.
        *
-       * @param {NamedData} data - Object of key-value pairs
+       * @param {Record<string, Data | Record<string, Data>>} data - Object of key-value pairs
        * @param {string} store - Datastore in which to put records
        * @returns {Promise<(IDBValidKey | DOMException)[]>} Index keys of the records inserted
        */
-       static async put<T extends Data> (data: NamedData<T>, store: string): Promise<(IDBValidKey | DOMException)[]> {
+       static async put<T extends Data | Record<string, Data>> (data: Record<string, T>, store: string): Promise<(IDBValidKey | DOMException)[]> {
                this.#storage ??= await this.#open(this.DB_NAME)
                const transaction = this.#storage.transaction(store, 'readwrite')
                const db = transaction.objectStore(store)
index a20f4de286fe1df832d9b7d81996f3b2435dab5f..acc04f2f7ee42b415ad266c24e3e0b0b54884633 100644 (file)
@@ -1,7 +1,6 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { NamedData } from '#types'
 import { Account } from './account'
 import { Database } from './database'
 import { Tools } from './tools'
@@ -55,11 +54,10 @@ export class Rolodex {
                        if (existingName === name) {
                                return true
                        }
-                       const data: NamedData = {
-                               [address]: {
-                                       id: address,
-                                       name
-                               }
+                       const data: { [address: string]: { id: string, name: string } } | { [name: string]: { id: string, addresses: string[] } } = {}
+                       data[address] = {
+                               id: address,
+                               name
                        }
                        if (existingName != null) {
                                const addresses = (await this.getAddresses(existingName))
@@ -76,7 +74,7 @@ export class Rolodex {
                                id: name,
                                addresses
                        }
-                       const results = await Database.put(data, this.DB_NAME)
+                       const results = await Database.put<Record<string, string | string[]>>(data, this.DB_NAME)
                        if (results.length !== Object.keys(data).length) {
                                throw new Error('Unexpected results from adding address', { cause: results })
                        }
@@ -132,7 +130,7 @@ export class Rolodex {
        */
        static async getAddresses (name: string): Promise<string[]> {
                try {
-                       const records = await Database.get<NamedData<string[]>>(name, this.DB_NAME)
+                       const records = await Database.get<Record<string, string[]>>(name, this.DB_NAME)
                        const record = records[name]
                        return record?.addresses
                                ? record.addresses.sort()
@@ -150,7 +148,7 @@ export class Rolodex {
        */
        static async getAllNames (): Promise<string[]> {
                try {
-                       const records = await Database.getAll<NamedData>(this.DB_NAME)
+                       const records = await Database.getAll<string>(this.DB_NAME)
                        return Object.keys(records).filter(v => v.slice(0, 5) !== 'nano_')
                } catch (err) {
                        console.error(err)
@@ -166,7 +164,7 @@ export class Rolodex {
        */
        static async getName (address: string): Promise<string | null> {
                try {
-                       const records = await Database.get<NamedData<string>>(address, this.DB_NAME)
+                       const records = await Database.get<Record<string, string>>(address, this.DB_NAME)
                        const record = records[address]
                        return record?.name ?? null
                } catch (err) {
index e9459bbac5173d5b65f3f5af193acbaead1cdf01..dcd7decfb916f4929501c3ba6196e7c329897275 100644 (file)
@@ -2,16 +2,16 @@
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
 import { Worker as NodeWorker } from 'node:worker_threads'
-import { Data, NamedData } from '#types'
 import { default as CONSTANTS } from '../constants'
 import { Bip39, Bip44, Blake2b, NanoNaCl, WalletAesGcm } from '../crypto'
+import { Data } from '../database'
 import { Passkey } from './passkey'
 import { VaultTimer } from './vault-timer'
 import { VaultWorker } from './vault-worker'
 
 type Task = {
        id: number
-       data: NamedData
+       data: Record<string, Data | Record<string, Data>>
        reject: (value: any) => void
        resolve: (value: any) => void
 }
@@ -51,10 +51,9 @@ export class Vault {
                })
        }
 
-
        get isLocked (): boolean { return this.#isLocked }
 
-       request<T extends Data> (data: NamedData): Promise<NamedData<T>> {
+       request<T extends Data | Record<string, Data>> (data: Record<string, Data | Record<string, Data>>): Promise<Record<string, T>> {
                return new Promise((resolve, reject): void => {
                        if (this.#isTerminated) {
                                return reject('Worker terminated')
@@ -83,9 +82,9 @@ export class Vault {
                        const { data, reject } = this.#job
                        try {
                                const buffers: ArrayBuffer[] = []
-                               for (let d of Object.keys(data)) {
-                                       if (data[d] instanceof ArrayBuffer) {
-                                               buffers.push(data[d])
+                               for (const d of Object.values(data)) {
+                                       if (d instanceof ArrayBuffer) {
+                                               buffers.push(d)
                                        }
                                }
                                BROWSER: this.#worker.postMessage(data, buffers)
index 825e205eb79a0ecfb3a2462601633f98fceeea68..faa1ae9cbb2bab325c8a4eb2757a47c403c77f77 100644 (file)
@@ -1,7 +1,6 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { NamedData } from '#types'
 import { BIP44_COIN_NANO } from '../constants'
 import { Bip39, Bip44, Blake2b, NanoNaCl, WalletAesGcm } from '../crypto'
 import { WalletType } from '../wallet'
@@ -35,7 +34,7 @@ export class VaultWorker {
                        const action = this.#parseAction(data)
                        const keySalt = this.#parseKeySalt(action, data)
                        Passkey.create(action, keySalt, data)
-                               .then((key: CryptoKey | undefined): Promise<NamedData | void> => {
+                               .then((key: CryptoKey | undefined): Promise<Record<string, boolean | number | ArrayBuffer> | void> => {
                                        const type = this.#parseType(action, data)
                                        const iv = this.#parseIv(action, data)
                                        const { seed, mnemonicPhrase, mnemonicSalt, index, encrypted, message, timeout } = this.#extractData(action, data)
@@ -76,12 +75,12 @@ export class VaultWorker {
                                                }
                                        }
                                })
-                               .then((result: NamedData | void) => {
+                               .then((result: Record<string, boolean | number | ArrayBuffer> | void) => {
                                        const transfer = []
                                        if (result) {
-                                               for (const k of Object.keys(result)) {
-                                                       if (result[k] instanceof ArrayBuffer || result[k] instanceof CryptoKey) {
-                                                               transfer.push(result[k])
+                                               for (const r of Object.values(result)) {
+                                                       if (r instanceof ArrayBuffer) {
+                                                               transfer.push(r)
                                                        }
                                                }
                                        }
@@ -91,11 +90,11 @@ export class VaultWorker {
                                })
                                .catch((err: any) => {
                                        console.error(err)
-                                       for (const key of Object.keys(event.data)) {
-                                               if (event.data[key] instanceof ArrayBuffer && !event.data[key].detached) {
-                                                       new Uint8Array(event.data[key]).fill(0).buffer.transfer?.()
+                                       for (let data of Object.values(event.data)) {
+                                               if (data instanceof ArrayBuffer && !data.detached) {
+                                                       new Uint8Array(data).fill(0).buffer.transfer?.()
                                                }
-                                               event.data[key] = undefined
+                                               data = undefined
                                        }
                                        BROWSER: postMessage({ error: 'Failed to process Vault request', cause: err })
                                        NODE: this.#parentPort?.postMessage({ error: 'Failed to process Vault request', cause: err })
@@ -145,7 +144,7 @@ export class VaultWorker {
        * Generates a new mnemonic and seed and then returns the initialization vector
        * vector, salt, and encrypted data representing the wallet in a locked state.
        */
-       create (type?: WalletType, key?: CryptoKey, keySalt?: ArrayBuffer, mnemonicSalt?: string): Promise<NamedData<ArrayBuffer>> {
+       create (type?: WalletType, key?: CryptoKey, keySalt?: ArrayBuffer, mnemonicSalt?: string): Promise<Record<string, ArrayBuffer>> {
                if (type !== 'BIP-44' && type !== 'BLAKE2b') {
                        throw new TypeError('Unsupported software wallet algorithm', { cause: type })
                }
@@ -173,7 +172,7 @@ export class VaultWorker {
        * wallet seed at a specified index and then returns the public key. The wallet
        * must be unlocked prior to derivation.
        */
-       derive (index?: number): Promise<NamedData<number | ArrayBuffer>> {
+       derive (index?: number): Promise<Record<string, number | ArrayBuffer>> {
                try {
                        this.#timer.pause()
                        if (this.#locked) {
@@ -207,7 +206,7 @@ export class VaultWorker {
        * Encrypts an existing seed or mnemonic+salt and returns the initialization
        * vector, salt, and encrypted data representing the wallet in a locked state.
        */
-       load (type?: WalletType, key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise<NamedData<ArrayBuffer>> {
+       load (type?: WalletType, key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise<Record<string, ArrayBuffer>> {
                if (type !== 'BIP-44' && type !== 'BLAKE2b') {
                        throw new TypeError('Unsupported software wallet algorithm', { cause: type })
                }
@@ -239,7 +238,7 @@ export class VaultWorker {
        * Derives the account private key at a specified index, signs the input data,
        * and returns a signature. The wallet must be unlocked prior to verification.
        */
-       sign (index?: number, data?: ArrayBuffer): Promise<NamedData<ArrayBuffer>> {
+       sign (index?: number, data?: ArrayBuffer): Promise<Record<string, ArrayBuffer>> {
                try {
                        this.#timer.pause()
                        if (this.#locked) {
@@ -318,7 +317,7 @@ export class VaultWorker {
        /**
        * Re-encrypts the wallet with a new password.
        */
-       update (key?: CryptoKey, salt?: ArrayBuffer): Promise<NamedData<ArrayBuffer>> {
+       update (key?: CryptoKey, salt?: ArrayBuffer): Promise<Record<string, ArrayBuffer>> {
                try {
                        this.#timer.pause()
                        if (this.#locked) {
@@ -349,7 +348,7 @@ export class VaultWorker {
        * Checks the seed and, if it exists, the mnemonic against input. The wallet
        * must be unlocked prior to verification.
        */
-       verify (seed?: ArrayBuffer, mnemonicPhrase?: string): NamedData<boolean> {
+       verify (seed?: ArrayBuffer, mnemonicPhrase?: string): Record<string, boolean> {
                try {
                        if (this.#locked) {
                                throw new Error('Wallet is locked')
@@ -492,7 +491,7 @@ export class VaultWorker {
        * Encrypts an existing seed or mnemonic+salt and returns the initialization
        * vector, salt, and encrypted data representing the wallet in a locked state.
        */
-       #load (type?: 'BIP-44' | 'BLAKE2b', key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise<NamedData<ArrayBuffer>> {
+       #load (type?: 'BIP-44' | 'BLAKE2b', key?: CryptoKey, keySalt?: ArrayBuffer, secret?: string | ArrayBuffer, mnemonicSalt?: string): Promise<Record<string, ArrayBuffer>> {
                try {
                        if (!this.#locked) {
                                throw new Error('Wallet is in use')
index 860ecd31e93f7b57eb384c233cc3c5f9f06293e0..bb8992ffa4c6cc411304127998078ea0f56931f3 100644 (file)
@@ -1,23 +1,18 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { NamedData } from '#types'
 import { Database } from '../database'
 import { Wallet } from '../wallet'
 
 export async function _backup () {
        try {
-               const records = await Database.getAll<NamedData>(Wallet.DB_NAME)
-               const recordIds = Object.keys(records)
-               return recordIds.map(recordId => {
-                       const { id, type, iv, salt, encrypted } = records[recordId]
+               const records = await Database.getAll<Record<string, string | ArrayBuffer>>(Wallet.DB_NAME)
+               return Object.values(records).map((record: Record<string, unknown>) => {
+                       const { id, type, iv, salt, encrypted } = record
                        if (typeof id !== 'string') {
                                throw new TypeError('Retrieved invalid ID', { cause: id })
                        }
-                       if (type === 'Ledger') {
-                               return { id, type, iv: new ArrayBuffer(0), salt: new ArrayBuffer(0), encrypted: new ArrayBuffer(0) } as const
-                       }
-                       if (type !== 'BIP-44' && type !== 'BLAKE2b') {
+                       if (type !== 'BIP-44' && type !== 'BLAKE2b' && type !== 'Ledger') {
                                throw new TypeError('Retrieved invalid type', { cause: type })
                        }
                        if (!(iv instanceof ArrayBuffer)) {
index 20f44a9c70ef20ce1ee925b6d1ad7c263290f068..cae4c49cdd2b5473f0c33ad4c099c16dd30ee2b4 100644 (file)
@@ -1,38 +1,31 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { NamedData } from '#types'
 import { utf8 } from '../convert'
 import { Database } from '../database'
 import { Ledger } from '../ledger'
 import { Vault } from '../vault'
 import { Wallet } from '../wallet'
-import { _load } from './load'
 
-export async function _create (wallet: Wallet, vault: Vault, password?: string, mnemonicSalt?: string): Promise<NamedData<ArrayBuffer>>
-export async function _create (wallet: Wallet, vault: Vault, password: unknown, mnemonicSalt?: unknown): Promise<NamedData<ArrayBuffer>> {
+export async function _create (wallet: Wallet, vault: Vault, password?: string, mnemonicSalt?: string): Promise<{ mnemonic?: ArrayBuffer, seed?: ArrayBuffer }>
+export async function _create (wallet: Wallet, vault: Vault, password: unknown, mnemonicSalt?: unknown): Promise<{ mnemonic?: ArrayBuffer, seed?: ArrayBuffer }> {
        try {
-               const result: NamedData<ArrayBuffer> = {}
-               const record: NamedData = {
+               const result: { mnemonic?: ArrayBuffer, seed?: ArrayBuffer } = {}
+               const record = {
                        id: wallet.id,
-                       type: wallet.type
+                       type: wallet.type,
+                       iv: new ArrayBuffer(0),
+                       salt: new ArrayBuffer(0),
+                       encrypted: new ArrayBuffer(0)
                }
-               if (wallet.type === 'Ledger') {
-                       try {
-                               if (Ledger.isUnsupported) {
-                                       throw new Error('Browser is unsupported')
-                               }
-                       } catch (err) {
-                               throw new Error('Failed to initialize Ledger wallet', { cause: err })
-                       }
-               } else {
+               if (wallet.type !== 'Ledger') {
                        if (typeof password !== 'string') {
                                throw new TypeError('Password must be a string')
                        }
                        if (mnemonicSalt !== undefined && typeof mnemonicSalt !== 'string') {
                                throw new TypeError('Mnemonic salt must be a string')
                        }
-                       const response = await vault.request<ArrayBuffer>({
+                       const pending = vault.request<ArrayBuffer>({
                                action: 'create',
                                type: wallet.type,
                                password: utf8.toBuffer(password),
@@ -40,11 +33,16 @@ export async function _create (wallet: Wallet, vault: Vault, password: unknown,
                        })
                        password = undefined
                        mnemonicSalt = undefined
+                       const response = await pending
                        record.iv = response.iv
                        record.salt = response.salt
                        record.encrypted = response.encrypted
                        result.mnemonic = response.mnemonic
                        result.seed = response.seed
+               } else {
+                       if (Ledger.isUnsupported) {
+                               throw new Error('Failed to initialize Ledger wallet', { cause: 'Browser is unsupported' })
+                       }
                }
                await Database.add({ [wallet.id]: record }, Wallet.DB_NAME)
                return result
index 2d8d3528b9e88865702cbaa08835110d542a03f0..412befd272caeb0709b6b97dd9d50782fbcb528a 100644 (file)
@@ -1,13 +1,12 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { NamedData } from '#types'
 import { Database } from '../database'
 import { Wallet } from '../wallet'
 
 export async function _get (recordId: string) {
        try {
-               const record = await Database.get<NamedData>(recordId, Wallet.DB_NAME)
+               const record = await Database.get<Record<string, string | ArrayBuffer>>(recordId, Wallet.DB_NAME)
                const { id, type, iv, salt, encrypted } = record[recordId]
                if (typeof id !== 'string') {
                        throw new TypeError('Retrieved invalid ID', { cause: id })
@@ -15,16 +14,14 @@ export async function _get (recordId: string) {
                if (type !== 'BIP-44' && type !== 'BLAKE2b' && type !== 'Ledger') {
                        throw new TypeError('Retrieved invalid type', { cause: type })
                }
-               if (type !== 'Ledger') {
-                       if (!(iv instanceof ArrayBuffer)) {
-                               throw new TypeError('Retrieved invalid iv', { cause: iv })
-                       }
-                       if (!(salt instanceof ArrayBuffer)) {
-                               throw new TypeError('Retrieved invalid salt', { cause: salt })
-                       }
-                       if (!(encrypted instanceof ArrayBuffer)) {
-                               throw new TypeError('Retrieved invalid encrypted data', { cause: encrypted })
-                       }
+               if (!(iv instanceof ArrayBuffer)) {
+                       throw new TypeError('Retrieved invalid iv', { cause: iv })
+               }
+               if (!(salt instanceof ArrayBuffer)) {
+                       throw new TypeError('Retrieved invalid salt', { cause: salt })
+               }
+               if (!(encrypted instanceof ArrayBuffer)) {
+                       throw new TypeError('Retrieved invalid encrypted data', { cause: encrypted })
                }
                return { id, type, iv, salt, encrypted } as const
        } catch (err) {
index c042bdacd5762d0c8c7f0f48276c372fcd8f545b..0c287deb3b2aa523fc2edd7c3f55a7e860e87b6c 100644 (file)
@@ -1,7 +1,6 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>\r
 //! SPDX-License-Identifier: GPL-3.0-or-later\r
 \r
-import { NamedData } from '#types'\r
 import { Account } from '../account'\r
 import { Block } from '../block'\r
 import { ADDRESS_GAP } from '../constants'\r
@@ -47,9 +46,9 @@ export class Wallet {
        * Retrieves all wallets with encrypted secrets and unencrypted metadata from\r
        * the database.\r
        *\r
-       * @returns id, type, iv, salt, encrypted\r
+       * @returns Array of objects with properties: id, type, iv, salt, encrypted\r
        */\r
-       static async backup (): Promise<NamedData[]> {\r
+       static async backup () {\r
                return _backup()\r
        }\r
 \r
@@ -74,7 +73,9 @@ export class Wallet {
                this.#isInternal = true\r
                const self = new this(type)\r
                this.#isInternal = false\r
-               { ({ mnemonic: self.#mnemonic, seed: self.#seed } = await _create(self, self.#vault, password, mnemonicSalt)) }\r
+               const pending = _create(self, self.#vault, password, mnemonicSalt)\r
+               password = undefined\r
+               { ({ mnemonic: self.#mnemonic, seed: self.#seed } = await pending) }\r
                return self\r
        }\r
 \r
@@ -103,7 +104,9 @@ export class Wallet {
                this.#isInternal = true\r
                const self = new this(type)\r
                this.#isInternal = false\r
-               await _load(self, self.#vault, password, secret, mnemonicSalt)\r
+               const pending = _load(self, self.#vault, password, secret, mnemonicSalt)\r
+               password = undefined!\r
+               await pending\r
                return self\r
        }\r
 \r
@@ -371,7 +374,9 @@ export class Wallet {
        */\r
        async unlock (password: string): Promise<void>\r
        async unlock (password?: string): Promise<void> {\r
-               await _unlock(this, this.#vault, password)\r
+               const pending = _unlock(this, this.#vault, password)\r
+               password = undefined\r
+               await pending\r
        }\r
 \r
        /**\r
@@ -394,7 +399,9 @@ export class Wallet {
        * @param {string} password Used to re-encrypt the wallet\r
        */\r
        async update (password: string): Promise<void> {\r
-               await _update(this, this.#vault, password)\r
+               const pending = _update(this, this.#vault, password)\r
+               password = undefined!\r
+               await pending\r
        }\r
 \r
        /**\r
index dee3b5798353bba4a6998cec4979504b2c58896c..fc73b83f636343ea0f987ce4cac0c855b2e3097f 100644 (file)
@@ -1,7 +1,6 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { NamedData } from '#types'
 import { hex, utf8 } from '../convert'
 import { Bip39 } from '../crypto'
 import { Database } from '../database'
@@ -12,9 +11,12 @@ import { Wallet } from '../wallet'
 export async function _load (wallet: Wallet, vault: Vault, password: string, secret: string, mnemonicSalt?: string): Promise<void>
 export async function _load (wallet: Wallet, vault: Vault, password: unknown, secret: unknown, mnemonicSalt?: unknown): Promise<void> {
        try {
-               const record: NamedData = {
+               const record = {
                        id: wallet.id,
-                       type: wallet.type
+                       type: wallet.type,
+                       iv: new ArrayBuffer(0),
+                       salt: new ArrayBuffer(0),
+                       encrypted: new ArrayBuffer(0)
                }
                if (wallet.type === 'Ledger') {
                        if (Ledger.isUnsupported) {
@@ -33,7 +35,7 @@ export async function _load (wallet: Wallet, vault: Vault, password: unknown, se
                        if (mnemonicSalt !== undefined && typeof mnemonicSalt !== 'string') {
                                throw new TypeError('Mnemonic salt must be a string')
                        }
-                       const data: NamedData = {
+                       const data: Record<string, string | ArrayBuffer> = {
                                action: 'load',
                                type: wallet.type,
                                password: utf8.toBuffer(password)
index 0c7cadd36dda9f79097fe83995cda5a1fdd8d9bd..b6be2647eaeab4f216d4200fe60811ccd9df1356 100644 (file)
@@ -1,7 +1,6 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { NamedData } from '#types'
 import { utf8 } from '../convert'
 import { Ledger } from '../ledger'
 import { Vault } from '../vault'
@@ -11,30 +10,30 @@ import { _get } from './get'
 export async function _unlock (wallet: Wallet, vault: Vault, password?: string): Promise<void>
 export async function _unlock (wallet: Wallet, vault: Vault, password: unknown): Promise<void> {
        try {
-               const data: NamedData = {
-                       action: 'unlock',
-                       type: wallet.type
-               }
-               if (wallet.type === 'Ledger') {
+               if (wallet.type !== 'Ledger') {
+                       if (typeof password !== 'string') {
+                               throw new TypeError('Password must be a string')
+                       }
+                       const data = {
+                               action: 'unlock',
+                               type: wallet.type,
+                               password: utf8.toBuffer(password),
+                               iv: new ArrayBuffer(0),
+                               keySalt: new ArrayBuffer(0),
+                               encrypted: new ArrayBuffer(0)
+                       }
+                       password = undefined
+                       const record = await _get(wallet.id)
+                       data.iv = record.iv
+                       data.keySalt = record.salt
+                       data.encrypted = record.encrypted
+                       await vault.request(data)
+               } else {
                        const status = await Ledger.connect()
                        if (await status !== 'CONNECTED') {
                                throw new Error('Failed to unlock wallet', { cause: status })
                        }
-                       data.password = new ArrayBuffer(0)
-                       data.iv = new ArrayBuffer(0)
-                       data.keySalt = new ArrayBuffer(0)
-                       data.encrypted = new ArrayBuffer(0)
-               } else {
-                       if (typeof password !== 'string') {
-                               throw new TypeError('Password must be a string')
-                       }
-                       const { iv, salt, encrypted } = await _get(wallet.id)
-                       data.password = utf8.toBuffer(password)
-                       data.iv = iv
-                       data.keySalt = salt
-                       data.encrypted = encrypted
                }
-               await vault.request(data)
                if (wallet.isLocked) {
                        throw new Error('Unlock request failed')
                }
index 1199c16fab124af658b2848e7b04bf344afd9e64..9859baf2fad7f6d995fefef26880dd7b84e7e0c0 100644 (file)
@@ -1,7 +1,6 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { NamedData } from '#types'
 import { utf8 } from '../convert'
 import { Database } from '../database'
 import { Vault } from '../vault'
@@ -10,26 +9,25 @@ import { Wallet } from '../wallet'
 export async function _update (wallet: Wallet, vault: Vault, password?: string): Promise<void>
 export async function _update (wallet: Wallet, vault: Vault, password: unknown): Promise<void> {
        try {
-               const record: NamedData = {
-                       id: wallet.id,
-                       type: wallet.type
-               }
-               if (wallet.type === 'Ledger') {
-                       return
-               } else {
+               if (wallet.type !== 'Ledger') {
                        if (typeof password !== 'string') {
                                throw new TypeError('Password must be a string')
                        }
-                       const response = await vault.request<ArrayBuffer>({
+                       const pending = vault.request<ArrayBuffer>({
                                action: 'update',
                                password: utf8.toBuffer(password)
                        })
                        password = undefined
-                       record.iv = response.iv
-                       record.salt = response.salt
-                       record.encrypted = response.encrypted
+                       const response = await pending
+                       const record = {
+                               id: wallet.id,
+                               type: wallet.type,
+                               iv: response.iv,
+                               salt: response.salt,
+                               encrypted: response.encrypted
+                       }
+                       await Database.put({ [wallet.id]: record }, Wallet.DB_NAME)
                }
-               await Database.put({ [wallet.id]: record }, Wallet.DB_NAME)
        } catch (err) {
                throw new Error('Failed to unlock wallet', { cause: err })
        }
diff --git a/src/types.d.ts b/src/types.d.ts
deleted file mode 100644 (file)
index 0daa045..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
-//! SPDX-License-Identifier: GPL-3.0-or-later
-
-export type Data = boolean | number | number[] | string | string[] | ArrayBuffer | CryptoKey | { [key: string]: Data }
-
-export type NamedData<T extends Data = Data> = {
-       [key: string]: T
-}