From: Chris Duncan Date: Thu, 31 Jul 2025 21:40:37 +0000 (-0700) Subject: Complete merge of wallet types. X-Git-Tag: v0.10.5~47^2~37 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=2a19f6d12817f3184b371c6d457af69554cf76a2;p=libnemo.git Complete merge of wallet types. --- diff --git a/src/lib/safe/bip44-ckd.ts b/src/lib/bip44-ckd.ts similarity index 100% rename from src/lib/safe/bip44-ckd.ts rename to src/lib/bip44-ckd.ts diff --git a/src/lib/safe/blake2b-ckd.ts b/src/lib/blake2b-ckd.ts similarity index 100% rename from src/lib/safe/blake2b-ckd.ts rename to src/lib/blake2b-ckd.ts diff --git a/src/lib/wallets/ledger-wallet.ts b/src/lib/ledger.ts similarity index 97% rename from src/lib/wallets/ledger-wallet.ts rename to src/lib/ledger.ts index 46d62a9..276b1fd 100644 --- a/src/lib/wallets/ledger-wallet.ts +++ b/src/lib/ledger.ts @@ -5,7 +5,7 @@ import { ledgerUSBVendorId } from '@ledgerhq/devices' import { default as TransportBLE } from '@ledgerhq/hw-transport-web-ble' import { default as TransportUSB } from '@ledgerhq/hw-transport-webusb' import { default as TransportHID } from '@ledgerhq/hw-transport-webhid' -import { Wallet } from '.' +import { Wallet } from './wallets' import { ChangeBlock, ReceiveBlock, SendBlock } from '#src/lib/block.js' import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET, LEDGER_ADPU_CODES, LEDGER_STATUS_CODES } from '#src/lib/constants.js' import { bytes, dec, hex } from '#src/lib/convert.js' diff --git a/src/lib/safe/safe.ts b/src/lib/safe.ts similarity index 98% rename from src/lib/safe/safe.ts rename to src/lib/safe.ts index 4cb6468..89bb4c7 100644 --- a/src/lib/safe/safe.ts +++ b/src/lib/safe.ts @@ -4,12 +4,12 @@ 'use strict' import { parentPort } from 'node:worker_threads' -import { Bip39Words } from '../bip39-wordlist' +import { Bip39Words } from './bip39-wordlist' import { Bip44Ckd } from './bip44-ckd' import { Blake2bCkd } from './blake2b-ckd' -import { NanoNaCl } from '../nano-nacl' +import { NanoNaCl } from './safe/nano-nacl' import { Bip39Mnemonic } from '#src/lib/bip39-mnemonic.js' -import { bytes, dec, hex, utf8 } from '#src/lib/convert.js' +import { default as Convert, bytes, hex, utf8 } from '#src/lib/convert.js' import { NamedData } from '#src/types.js' /** @@ -457,5 +457,7 @@ let importWorkerThreads = '' NODE: importWorkerThreads = `import { parentPort } from 'node:worker_threads'` export default ` ${importWorkerThreads} + ${Convert} + const Bip39Words = ${Bip39Words} const Safe = ${Safe} ` diff --git a/src/lib/safe/index.ts b/src/lib/safe/index.ts deleted file mode 100644 index e944442..0000000 --- a/src/lib/safe/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -//! SPDX-FileCopyrightText: 2025 Chris Duncan -//! SPDX-License-Identifier: GPL-3.0-or-later - -export { SafeWorker } from './worker-queue' diff --git a/src/lib/safe/nano-nacl.ts b/src/lib/safe/nano-nacl.ts index 0e8c8c2..44afc7d 100644 --- a/src/lib/safe/nano-nacl.ts +++ b/src/lib/safe/nano-nacl.ts @@ -4,7 +4,7 @@ 'use strict' import { Blake2b } from '#src/lib/blake2b.js' -import { default as Convert, hex } from '#src/lib/convert.js' +import { hex } from '#src/lib/convert.js' import { Key, NamedData } from '#types' /** diff --git a/src/lib/safe/worker-interface.ts b/src/lib/safe/worker-interface.ts deleted file mode 100644 index abd5899..0000000 --- a/src/lib/safe/worker-interface.ts +++ /dev/null @@ -1,101 +0,0 @@ -//! SPDX-FileCopyrightText: 2025 Chris Duncan -//! SPDX-License-Identifier: GPL-3.0-or-later - -import { parentPort } from 'node:worker_threads' -import { NamedData } from '#types' - -/** -* Provides basic worker event messaging to extending classes. -* -* In order to be properly bundled in a format that can be used to create an -* inline Web Worker, the extending classes must export WorkerInterface and -* themselves as a string: -*``` -* export default ` -* const WorkerInterface = ${WorkerInterface} -* const WorkerImplementation = ${WorkerImplementation} -* ` -* ``` -* They must also initialize the event listener by calling their inherited -* `listen()` function. Finally, they must override the implementation of the -* `work()` function. See the documentation of those functions for details. -*/ -export abstract class WorkerInterface { - static parentPort: any - static { - NODE: this.parentPort = parentPort - } - /** - * Processes data through a worker. - * - * Extending classes must override this template by implementing the same - * function signature and providing their own processing call in the try-catch - * block. - * - * @param {NamedData} data - Flat object of data key-value pairs - * @returns Promise for processed data - */ - static work (data: NamedData): Promise { - return new Promise((resolve, reject): void => { - try { - if (data == null) { - throw new Error('Missing data') - } - const { x, y } = data - resolve({ x, y }) - } catch (err) { - reject(err) - } - }) - } - - /** - * Transfers buffers of worker results back to the main thread. - * - * @param {NamedData} data - Key-value pairs of processed data - */ - static report (data: NamedData): void { - const buffers = [] - try { - if (typeof data === 'object') { - for (const d of Object.keys(data)) { - if (data[d] instanceof ArrayBuffer) { - buffers.push(data[d]) - } - } - } - } catch (err) { - console.error(err) - throw new Error('Failed to report results', { cause: err }) - } - //@ts-expect-error - BROWSER: postMessage(data, buffers) - NODE: parentPort?.postMessage(data, buffers) - } - - /** - * Listens for messages from the main thread. - * - * Extending classes must call this in a static initialization block: - * ``` - * static { - * Extension.listen() - * } - * ``` - */ - static listen (): void { - const listener = async (message: MessageEvent): Promise => { - // console.log(message) - const { data } = message - if (data.method === 'STOP') { - this.report({}) - BROWSER: close() - NODE: process.exit() - } else { - this.work(data).then(this.report).catch(this.report) - } - } - BROWSER: addEventListener('message', listener) - NODE: this.parentPort?.on('message', listener) - } -} diff --git a/src/lib/wallets/wallet.ts b/src/lib/wallet.ts similarity index 78% rename from src/lib/wallets/wallet.ts rename to src/lib/wallet.ts index 0156598..cb907d9 100644 --- a/src/lib/wallets/wallet.ts +++ b/src/lib/wallet.ts @@ -9,8 +9,9 @@ import { bytes, hex, utf8 } from '#src/lib/convert.js' import { Database } from '#src/lib/database.js' import { Entropy } from '#src/lib/entropy.js' import { Rpc } from '#src/lib/rpc.js' +import { default as SafeWorker } from '#src/lib/safe.js' +import { WorkerQueue } from '#src/lib/worker-queue.js' import { KeyPair, NamedData, WalletType } from '#types' -import { SafeWorker } from '#workers' /** * Represents a wallet containing numerous Nano accounts derived from a single @@ -21,6 +22,24 @@ import { SafeWorker } from '#workers' */ export class Wallet { static #DB_NAME = 'Wallet' + static #isInternal: boolean = false + + /** + * Retrieves a wallet from the database. + */ + static async #get (name: string) { + try { + const record = await Database.get(name, this.#DB_NAME) + const decoded = JSON.parse(record[name]) + const type: 'BIP-44' | 'BLAKE2b' = decoded.type + const iv: ArrayBuffer = hex.toBuffer(decoded.iv) + const salt: ArrayBuffer = hex.toBuffer(decoded.salt) + const encrypted: ArrayBuffer = hex.toBuffer(decoded.encrypted) + return { type, iv, salt, encrypted } + } catch (err) { + throw new Error('Failed to get wallet from database', { cause: err }) + } + } /** * Creates a new HD wallet by using an entropy value generated using a @@ -31,8 +50,10 @@ export class Wallet { * @returns {Bip44Wallet} A newly instantiated Wallet */ static async create (name: string, type: 'BIP-44' | 'BLAKE2b', password: string, mnemonicSalt?: string): Promise { + Wallet.#isInternal = true + const self = new this(name, type) try { - const { iv, salt, encrypted } = await SafeWorker.request({ + const { iv, salt, encrypted } = await self.#safe.request({ action: 'create', type, password: utf8.toBuffer(password), @@ -44,27 +65,49 @@ export class Wallet { salt: bytes.toHex(new Uint8Array(salt)), encrypted: bytes.toHex(new Uint8Array(encrypted)) }) - await Database.put({ [name]: encoded }, this.#DB_NAME) - return new this(name, type) + await Database.put({ [name]: encoded }, Wallet.#DB_NAME) + return self } catch (err) { throw new Error('Error creating new Bip44Wallet', { cause: err }) } } + /** + * Retrieves an existing wallet from the database using its name. + * + * @param {string} name - Entered by user when the wallet was initially created + * @returns {Wallet} Restored locked Wallet + */ + static async restore (name: string): Promise { + try { + if (typeof name !== 'string' || name === '') { + throw new TypeError('Wallet name is required to restore') + } + const { type } = await this.#get(name) + Wallet.#isInternal = true + return new this(name, type) + } catch (err) { + throw new Error('Failed to restore wallet', { cause: err }) + } + } + #accounts: AccountList #lockTimer?: any #name: string + #safe: WorkerQueue #type: WalletType get name () { return `${this.type}_${this.#name}` } get type () { return this.#type } constructor (name: string, type: WalletType) { - if (this.constructor === Wallet) { - throw new Error('Wallet is an abstract class and cannot be instantiated directly.') + if (!Wallet.#isInternal) { + throw new Error(`Wallet cannot be instantiated directly. Use 'await Wallet.create()' instead.`) } + Wallet.#isInternal = false this.#accounts = new AccountList() this.#name = name + this.#safe = new WorkerQueue(SafeWorker) this.#type = type } @@ -129,17 +172,15 @@ export class Wallet { if (indexes.length > 0) { const promises = [] for (const index of indexes) { - promises.push(SafeWorker.request({ + promises.push(this.#safe.request({ action: 'derive', index })) } - const publicKeys = await Promise.all(promises) - const publicAccounts = publicKeys.length > 0 - ? Account.import(publicKeys) - : [] - const accounts = [...publicAccounts] - for (const a of accounts) { + const publicKeys: KeyPair[] = await Promise.all(promises) + if (publicKeys.length === 0) return [] + const publicAccounts = Account.import(publicKeys) + for (const a of publicAccounts) { if (a.index == null) { throw new RangeError('Index missing for Account') } @@ -170,7 +211,7 @@ export class Wallet { */ async lock (): Promise { try { - const { isLocked } = await SafeWorker.request({ + const { isLocked } = await this.#safe.request({ action: 'lock' }) if (!isLocked) { @@ -221,7 +262,7 @@ export class Wallet { */ async sign (index: number, block: ChangeBlock | ReceiveBlock | SendBlock): Promise { try { - const { signature } = await SafeWorker.request({ + const { signature } = await this.#safe.request({ action: 'sign', index, data: JSON.stringify(block) @@ -244,12 +285,8 @@ export class Wallet { */ async unlock (password: string): Promise { try { - const record = await Database.get(this.#name, Wallet.#DB_NAME) - const decoded = JSON.parse(record[this.#name]) - const iv: ArrayBuffer = hex.toBuffer(decoded.iv) - const salt: ArrayBuffer = hex.toBuffer(decoded.salt) - const encrypted: ArrayBuffer = hex.toBuffer(decoded.encrypted) - const { isUnlocked } = await SafeWorker.request({ + const { iv, salt, encrypted } = await Wallet.#get(this.#name) + const { isUnlocked } = await this.#safe.request({ action: 'unlock', password: utf8.toBuffer(password), iv, diff --git a/src/lib/wallets/bip44-wallet.ts b/src/lib/wallets/bip44-wallet.ts deleted file mode 100644 index a37b608..0000000 --- a/src/lib/wallets/bip44-wallet.ts +++ /dev/null @@ -1,172 +0,0 @@ -//! SPDX-FileCopyrightText: 2025 Chris Duncan -//! SPDX-License-Identifier: GPL-3.0-or-later - -import { Wallet } from '.' -import { Bip39Mnemonic } from '#src/lib/bip39-mnemonic.js' -import { SEED_LENGTH_BIP44 } from '#src/lib/constants.js' -import { hex } from '#src/lib/convert.js' -import { Entropy } from '#src/lib/entropy.js' -import { Key, KeyPair } from '#types' -import { SafeWorker } from '#workers' - -/** -* Hierarchical deterministic (HD) wallet created by using a source of entropy to -* derive a mnemonic phrase. The mnemonic phrase, in combination with an optional -* salt, is used to generate a seed. A value can be provided as a parameter for -* entropy, mnemonic + salt, or seed; if no argument is passed, a new entropy -* value will be generated using a cryptographically strong pseudorandom number -* generator. -* -* Importantly, the salt is not stored in the instantiated Wallet object. If a -* salt is used, then losing it means losing the ability to regenerate the seed -* from the mnemonic. -* -* Accounts are derived from the seed. Private keys are derived using a BIP-44 -* derivation path. The public key is derived from the private key using the -* Ed25519 key algorithm. Account addresses are derived as described in the nano -* documentation (https://docs.nano.org) -* -* A password must be provided when creating or importing the wallet and is used -* to lock and unlock the wallet. The wallet will be initialized as locked. When -* the wallet is unlocked, a new password can be specified using the lock() -* method. -*/ -export class Bip44Wallet extends Wallet { - static #isInternal: boolean = false - - private constructor (id: Entropy, seed?: Uint8Array, mnemonic?: Bip39Mnemonic) { - if (!Bip44Wallet.#isInternal) { - throw new Error(`Bip44Wallet cannot be instantiated directly. Use 'await Bip44Wallet.create()' instead.`) - } - Bip44Wallet.#isInternal = false - super(id.hex, 'BIP-44') - } - - /** - * Creates a new HD wallet by using an entropy value generated using a - * cryptographically strong pseudorandom number generator. - * - * @param {string} password - Encrypts the wallet to lock and unlock it - * @param {string} [salt=''] - Used when generating the final seed - * @returns {Bip44Wallet} A newly instantiated Bip44Wallet - */ - static async create (password: string, salt?: string): Promise - /** - * Creates a new HD wallet by using an entropy value generated using a - * cryptographically strong pseudorandom number generator. - * - * @param {Uint8Array} key - Encrypts the wallet to lock and unlock it - * @param {string} [salt=''] - Used when generating the final seed - * @returns {Bip44Wallet} A newly instantiated Bip44Wallet - */ - static async create (key: Uint8Array, salt?: string): Promise - static async create (passkey: Key, salt: string = ''): Promise { - try { - const e = await Entropy.create() - return await Bip44Wallet.fromEntropy(passkey as string, e.hex, salt) - } catch (err) { - throw new Error('Error creating new Bip44Wallet', { cause: err }) - } - } - - /** - * Creates a new HD wallet by using a pregenerated entropy value. The user - * must ensure that it is cryptographically strongly random. - * - * @param {string} password - Used to lock and unlock the wallet - * @param {string} entropy - Used when generating the initial mnemonic phrase - * @param {string} [salt=''] - Used when generating the final seed - * @returns {Bip44Wallet} A newly instantiated Bip44Wallet - */ - static async fromEntropy (password: string, entropy: string, salt: string = ''): Promise { - let wallet: Bip44Wallet - try { - const id = await Entropy.create() - const e = await Entropy.import(entropy) - const m = await Bip39Mnemonic.fromEntropy(e.hex) - const s = await m.toBip39Seed(salt) - Bip44Wallet.#isInternal = true - wallet = new this(id, s, m) - } catch (err) { - throw new Error('Error importing Bip44Wallet from entropy', { cause: err }) - } - try { - await wallet.lock() - } catch (err) { - await wallet.destroy() - throw new Error('Error locking Bip44Wallet while importing from entropy', { cause: err }) - } - return wallet - } - - /** - * Creates a new HD wallet by using a pregenerated mnemonic phrase. - * - * @param {string} password - Used to lock and unlock the wallet - * @param {string} mnemonic - Used when generating the final seed - * @param {string} [salt=''] - Used when generating the final seed - * @returns {Bip44Wallet} A newly instantiated Bip44Wallet - */ - static async fromMnemonic (password: string, mnemonic: string, salt: string = ''): Promise { - let wallet: Bip44Wallet - try { - const id = await Entropy.create() - const m = await Bip39Mnemonic.fromPhrase(mnemonic) - const s = await m.toBip39Seed(salt) - Bip44Wallet.#isInternal = true - wallet = new this(id, s, m) - } catch (err) { - throw new Error('Error importing Bip44Wallet from mnemonic', { cause: err }) - } - try { - await wallet.lock() - } catch (err) { - await wallet.destroy() - throw new Error('Error locking Bip44Wallet while importing from mnemonic', { cause: err }) - } - return wallet - } - - /** - * Creates a new HD wallet by using a pregenerated seed value. This seed cannot - * be used to regenerate any higher level randomness which includes entropy, - * mnemonic phrase, and salt. - * - * @param {string} password - Used to lock and unlock the wallet - * @param {string} seed - Hexadecimal 128-character string used to derive private-public key pairs - * @returns {Bip44Wallet} A newly instantiated Bip44Wallet - */ - static async fromSeed (password: string, seed: string): Promise { - if (seed.length !== SEED_LENGTH_BIP44) { - throw new Error(`Expected a ${SEED_LENGTH_BIP44}-character seed, but received ${seed.length}-character string.`) - } - if (!/^[0-9a-fA-F]+$/i.test(seed)) { - throw new Error('Seed contains invalid hexadecimal characters.') - } - const id = await Entropy.create() - Bip44Wallet.#isInternal = true - const wallet = new this(id, hex.toBytes(seed)) - try { - await wallet.lock() - } catch (err) { - await wallet.destroy() - throw new Error('Error locking Bip44Wallet while importing from seed', { cause: err }) - } - return wallet - } - - /** - * Retrieves an existing HD wallet from storage using its ID. - * - * @param {string} id - Generated when the wallet was initially created - * @returns {Bip44Wallet} Restored locked Bip44Wallet - */ - static async restore (id: string): Promise { - if (typeof id !== 'string' || id === '') { - throw new TypeError('Wallet ID is required to restore') - } - id = id.replace('BIP-44_', '') - Bip44Wallet.#isInternal = true - return new this(await Entropy.import(id)) - } -} diff --git a/src/lib/wallets/blake2b-wallet.ts b/src/lib/wallets/blake2b-wallet.ts deleted file mode 100644 index 57279c6..0000000 --- a/src/lib/wallets/blake2b-wallet.ts +++ /dev/null @@ -1,135 +0,0 @@ -//! SPDX-FileCopyrightText: 2025 Chris Duncan -//! SPDX-License-Identifier: GPL-3.0-or-later - -import { Wallet } from '.' -import { Bip39Mnemonic } from '#src/lib/bip39-mnemonic.js' -import { Blake2b } from '#src/lib/blake2b.js' -import { SEED_LENGTH_BLAKE2B } from '#src/lib/constants.js' -import { hex, utf8 } from '#src/lib/convert.js' -import { Entropy } from '#src/lib/entropy.js' -import { Key, KeyPair } from '#types' - -/** -* BLAKE2b wallet created by deriving a mnemonic phrase from a seed or vice -* versa. If no value is provided for either, a new BIP-39 seed and mnemonic will -* be generated using a cryptographically strong pseudorandom number generator. -* -* Account private keys are derived on an ad hoc basis using the Blake2b hashing -* function. Account public key are derived from the private key using the -* Ed25519 key algorithm. Account addresses are derived from the public key as -* described in the Nano documentation. -* https://docs.nano.org/integration-guides/the-basics/ -* -* A password must be provided when creating or importing the wallet and is used -* to lock and unlock the wallet. The wallet will be initialized as locked. When -* the wallet is unlocked, a new password can be specified using the lock() -* method. -*/ -export class Blake2bWallet extends Wallet { - static #isInternal: boolean = false - - private constructor (id: Entropy, seed?: Uint8Array, mnemonic?: Bip39Mnemonic) { - if (!Blake2bWallet.#isInternal) { - throw new Error(`Blake2bWallet cannot be instantiated directly. Use 'await Blake2bWallet.create()' instead.`) - } - Blake2bWallet.#isInternal = false - super(id.hex, 'BLAKE2b') - } - - /** - * Creates a new BLAKE2b wallet by using a seed generated using a - * cryptographically strong pseudorandom number generator. - * - * @param {string} password - Encrypts the wallet to lock and unlock it - * @returns {Blake2bWallet} A newly instantiated Blake2bWallet - */ - static async create (password: string): Promise - /** - * Creates a new BLAKE2b wallet by using a seed generated using a - * cryptographically strong pseudorandom number generator. - * - * @param {Uint8Array} key - Encrypts the wallet to lock and unlock it - * @returns {Blake2bWallet} A newly instantiated Blake2bWallet - */ - static async create (key: Uint8Array): Promise - static async create (passkey: string | Uint8Array): Promise { - try { - const seed = await Entropy.create() - return await Blake2bWallet.fromSeed(passkey as string, seed.hex) - } catch (err) { - throw new Error('Error creating new Blake2bWallet', { cause: err }) - } - } - - /** - * Creates a new BLAKE2b wallet by using a pregenerated seed. The user must - * ensure that it is cryptographically strongly random. - * - * @param {string} password - Used to lock and unlock the wallet - * @param {string} seed - Hexadecimal 64-character string used to derive private-public key pairs - * @returns {Blake2bWallet} A newly instantiated Blake2bWallet - */ - static async fromSeed (password: string, seed: string): Promise { - if (seed.length !== SEED_LENGTH_BLAKE2B) { - throw new Error(`Expected a ${SEED_LENGTH_BLAKE2B}-character seed, but received ${seed.length}-character string.`) - } - if (!/^[0-9a-fA-F]+$/i.test(seed)) { - throw new Error('Seed contains invalid hexadecimal characters.') - } - - const id = await Entropy.create() - const s = hex.toBytes(seed) - const m = await Bip39Mnemonic.fromEntropy(seed) - Blake2bWallet.#isInternal = true - const wallet = new this(id, s, m) - try { - await wallet.lock() - } catch (err) { - await wallet.destroy() - throw new Error('Error locking Blake2bWallet while importing from seed', { cause: err }) - } - return wallet - } - - /** - * Creates a new BLAKE2b wallet by using a pregenerated mnemonic phrase. - * - * @param {string} password - Used to lock and unlock the wallet - * @param {string} mnemonic - Used when generating the final seed - * @returns {Blake2bWallet} A newly instantiated Blake2bWallet - */ - static async fromMnemonic (password: string, mnemonic: string): Promise { - let wallet: Blake2bWallet - try { - const id = await Entropy.create() - const m = await Bip39Mnemonic.fromPhrase(mnemonic) - const s = await m.toBlake2bSeed() - Blake2bWallet.#isInternal = true - wallet = new this(id, s, m) - } catch (err) { - throw new Error('Error importing Blake2bWallet from mnemonic', { cause: err }) - } - try { - await wallet.lock() - } catch (err) { - await wallet.destroy() - throw new Error('Error locking Blake2bWallet while importing from mnemonic', { cause: err }) - } - return wallet - } - - /** - * Retrieves an existing BLAKE2b wallet from storage using its ID. - * - * @param {string} id - Generated when the wallet was initially created - * @returns {Blake2bWallet} Restored locked Blake2bWallet - */ - static async restore (id: string): Promise { - if (typeof id !== 'string' || id === '') { - throw new TypeError('Wallet ID is required to restore') - } - id = id.replace('BLAKE2b_', '') - Blake2bWallet.#isInternal = true - return new this(await Entropy.import(id)) - } -} diff --git a/src/lib/wallets/index.ts b/src/lib/wallets/index.ts deleted file mode 100644 index 94d687e..0000000 --- a/src/lib/wallets/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -//! SPDX-FileCopyrightText: 2025 Chris Duncan -//! SPDX-License-Identifier: GPL-3.0-or-later - -export { Wallet } from './wallet' -export { Bip44Wallet } from './bip44-wallet' -export { Blake2bWallet } from './blake2b-wallet' -export { LedgerWallet } from './ledger-wallet' diff --git a/src/lib/safe/worker-queue.ts b/src/lib/worker-queue.ts similarity index 98% rename from src/lib/safe/worker-queue.ts rename to src/lib/worker-queue.ts index 1143167..d69e565 100644 --- a/src/lib/safe/worker-queue.ts +++ b/src/lib/worker-queue.ts @@ -110,5 +110,3 @@ export class WorkerQueue { } } } - -export const SafeWorker = new WorkerQueue(safe)