//! 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.
/**
* 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)
*
* @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')
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
* 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)
} 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
}
/**
* 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)
//! 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'
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))
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 })
}
*/
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()
*/
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)
*/
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) {
//! 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
}
})
}
-
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')
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)
//! 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'
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)
}
}
})
- .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)
}
}
}
})
.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 })
* 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 })
}
* 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) {
* 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 })
}
* 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) {
/**
* 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) {
* 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')
* 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')
//! 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)) {
//! 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),
})
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
//! 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 })
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) {
//! 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
* 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
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
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
*/\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
* @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
//! 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'
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) {
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)
//! 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'
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')
}
//! 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'
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 })
}
+++ /dev/null
-//! 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
-}