"imports": {
"#dist/*": "./dist/*",
"#src/*": "./src/*",
- "#workers": "./src/lib/workers/index.js",
- "#workers/*": "./src/lib/workers/*"
+ "#workers": "./src/lib/workers/index.js"
},
"dependencies": {
"nano-pow": "^5.1.4"
import { Blake2b } from './blake2b'\r
import { ACCOUNT_KEY_BYTE_LENGTH, ACCOUNT_KEY_HEX_LENGTH, ALPHABET, PREFIX, PREFIX_LEGACY } from './constants'\r
import { base32, bytes, hex, obj, utf8 } from './convert'\r
-import { Queue } from './pool'\r
import { Rpc } from './rpc'\r
-import { NanoNaClWorker, SafeWorker } from '#workers'\r
+import { NanoNaClWorker, Queue, SafeWorker } from '#workers'\r
\r
/**\r
* Represents a single Nano address and the associated public key. To include the\r
import { Blake2b } from './blake2b'
import { BURN_ADDRESS, PREAMBLE, DIFFICULTY_RECEIVE, DIFFICULTY_SEND } from './constants'
import { dec, hex } from './convert'
-import { Queue } from './pool'
import { Rpc } from './rpc'
-import { NanoNaClWorker } from '#workers'
+import { NanoNaClWorker, Queue } from '#workers'
/**
* Represents a block as defined by the Nano cryptocurrency protocol. The Block
+++ /dev/null
-// SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-export type Headers = {
- [key: string]: any
-}
-
-export type Data = {
- [key: string]: ArrayBuffer
-}
-
-type Task = {
- id: number
- headers: Headers | null
- data?: Data
- reject: (value: any) => void
- resolve: (value: any) => void
-}
-
-/**
-* Processes a queue of tasks using Web Workers.
-*/
-export class Queue {
- static #decoder: TextDecoder = new TextDecoder()
- static #encoder: TextEncoder = new TextEncoder()
- static #instances: Queue[] = []
- static get instances (): Queue[] { return this.#instances }
-
- #job?: Task
- #isIdle: boolean
- #queue: Task[] = []
- #url: string
- #worker: Worker
-
- /**
- * Creates a Web Worker from a stringified script.
- *
- * @param {string} worker - Stringified worker class body
- * @param {number} [count=1] - Integer between 1 and CPU thread count shared among all Pools
- */
- constructor (worker: string) {
- this.#isIdle = true
- this.#queue = []
- this.#url = URL.createObjectURL(new Blob([worker], { type: 'text/javascript' }))
- this.#worker = new Worker(this.#url, { type: 'module' })
- this.#worker.addEventListener('message', message => {
- let result = JSON.parse(Queue.#decoder.decode(message.data) || '[]')
- if (!Array.isArray(result)) result = [result]
- debugger
- this.#report(result)
- })
- Queue.#instances.push(this)
- }
-
- async add (headers: Headers | null, data?: Data): Promise<any> {
- return await this.#assign(task => this.#queue.push(task), headers, data)
- }
-
- async prioritize (headers: Headers | null, data?: Data): Promise<any> {
- return await this.#assign(task => this.#queue.unshift(task), headers, data)
- }
-
- terminate (): void {
- this.#job = undefined
- this.#worker.terminate()
- }
-
- async #assign (enqueue: (task: Task) => number, headers: Headers | null, data?: Data) {
- return new Promise(async (resolve, reject): Promise<void> => {
- const task: Task = {
- id: performance.now(),
- headers,
- data,
- resolve,
- reject
- }
- await enqueue(task)
- debugger
- if (this.#isIdle) this.#process()
- })
- }
-
- #process = (): void => {
- debugger
- this.#job = this.#queue.shift()
- if (this.#job == null) {
- throw new Error('Failed to get job from empty task queue.')
- }
- const { id, headers, data, reject } = this.#job
- this.#isIdle = !id
- try {
- const buffers: ArrayBuffer[] = []
- if (data != null) {
- for (let d of Object.keys(data)) {
- buffers.push(data[d])
- }
- }
- this.#worker.postMessage({ headers, data }, buffers)
- } catch (err) {
- reject(err)
- }
- }
-
- #report (results: any[]): void {
- if (this.#job == null) {
- throw new Error('Worker returned results but had nowhere to report it.')
- }
- const { resolve, reject } = this.#job
- debugger
- try {
- resolve(results)
- } catch (err) {
- reject(err)
- } finally {
- this.#process()
- }
- }
-}
-
-/**
-* 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 Pow = ${Pow}
-* `
-* ```
-* 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 {
- /**
- * 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 {Header} headers - Flat object of header data
- * @param {any[]} data - Transferred buffer of data to process
- * @returns Promise for processed data
- */
- static async work (headers: Headers | null, data?: Data): Promise<any> {
- return new Promise(async (resolve, reject): Promise<void> => {
- try {
- let x, y
- if (headers != null) {
- const { sample } = headers
- x = sample
- }
- if (data != null) {
- const { buf } = data
- y = buf
- }
- resolve({ x, y })
- } catch (err) {
- reject(err)
- }
- })
- }
-
- /**
- * Encodes worker results as an ArrayBuffer so it can be transferred back to
- * the main thread.
- *
- * @param {any[]} results - Array of processed data
- */
- static report (results: any[]): void {
- const buffer = new TextEncoder().encode(JSON.stringify(results)).buffer
- //@ts-expect-error
- postMessage(buffer, [buffer])
- }
-
- /**
- * Listens for messages from the main thread.
- *
- * Extending classes must call this in a static initialization block:
- * ```
- * static {
- * Extension.listen()
- * }
- * ```
- */
- static listen (): void {
- addEventListener('message', (message: any): void => {
- const { name, headers, data } = message
- if (name === 'STOP') {
- close()
- const buffer = new ArrayBuffer(0)
- //@ts-expect-error
- postMessage(buffer, [buffer])
- } else {
- this.work(headers, data).then(this.report).catch(this.report)
- }
- })
- }
-}
import { SEED_LENGTH_BIP44 } from '#src/lib/constants.js'\r
import { hex, utf8 } from '#src/lib/convert.js'\r
import { Entropy } from '#src/lib/entropy.js'\r
-import { Queue } from '#src/lib/pool.js'\r
-import { Bip44CkdWorker } from '#workers'\r
+import { Bip44CkdWorker, Queue } from '#workers'\r
\r
/**\r
* Hierarchical deterministic (HD) wallet created by using a source of entropy to\r
import { ADDRESS_GAP } from '#src/lib/constants.js'\r
import { hex, utf8 } from '#src/lib/convert.js'\r
import { Entropy } from '#src/lib/entropy.js'\r
-import { Queue } from '#src/lib/pool.js'\r
import { Rpc } from '#src/lib/rpc.js'\r
-import { SafeWorker } from '#workers'\r
+import { Queue, SafeWorker } from '#workers'\r
\r
export { Bip44Wallet } from './bip44-wallet'\r
export { Blake2bWallet } from './blake2b-wallet'\r
import { default as TransportBLE } from '@ledgerhq/hw-transport-web-ble'\r
import { default as TransportUSB } from '@ledgerhq/hw-transport-webusb'\r
import { default as TransportHID } from '@ledgerhq/hw-transport-webhid'\r
+import { KeyPair, Wallet } from '.'\r
import { ChangeBlock, ReceiveBlock, SendBlock } from '#src/lib/block.js'\r
import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET, LEDGER_ADPU_CODES, LEDGER_STATUS_CODES } from '#src/lib/constants.js'\r
import { bytes, dec, hex } from '#src/lib/convert.js'\r
import { Entropy } from '#src/lib/entropy.js'\r
import { Rpc } from '#src/lib/rpc.js'\r
-import { KeyPair, Wallet } from '.'\r
\r
type DeviceStatus = 'DISCONNECTED' | 'BUSY' | 'LOCKED' | 'CONNECTED'\r
\r
// SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
// SPDX-License-Identifier: GPL-3.0-or-later
-import { Data, Headers, WorkerInterface } from '#src/lib/pool.js'
+
+import { Data, Headers, WorkerInterface } from '.'
type ExtendedKey = {
privateKey: DataView<ArrayBuffer>
// SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
// SPDX-License-Identifier: GPL-3.0-or-later
+
import { default as Bip44CkdWorker, Bip44Ckd } from './bip44-ckd'
import { default as NanoNaClWorker, NanoNaCl } from './nano-nacl'
import { default as SafeWorker, Safe } from './safe'
Safe,
SafeWorker
}
+
+export type Headers = {
+ [key: string]: any
+}
+
+export type Data = {
+ [key: string]: ArrayBuffer
+}
+
+type Task = {
+ id: number
+ headers: Headers | null
+ data?: Data
+ reject: (value: any) => void
+ resolve: (value: any) => void
+}
+
+/**
+* Processes a queue of tasks using Web Workers.
+*/
+export class Queue {
+ static #decoder: TextDecoder = new TextDecoder()
+ static #encoder: TextEncoder = new TextEncoder()
+ static #instances: Queue[] = []
+ static get instances (): Queue[] { return this.#instances }
+
+ #job?: Task
+ #isIdle: boolean
+ #queue: Task[] = []
+ #url: string
+ #worker: Worker
+
+ /**
+ * Creates a Web Worker from a stringified script.
+ *
+ * @param {string} worker - Stringified worker class body
+ * @param {number} [count=1] - Integer between 1 and CPU thread count shared among all Pools
+ */
+ constructor (worker: string) {
+ this.#isIdle = true
+ this.#queue = []
+ this.#url = URL.createObjectURL(new Blob([worker], { type: 'text/javascript' }))
+ this.#worker = new Worker(this.#url, { type: 'module' })
+ this.#worker.addEventListener('message', message => {
+ let result = JSON.parse(Queue.#decoder.decode(message.data) || '[]')
+ if (!Array.isArray(result)) result = [result]
+ debugger
+ this.#report(result)
+ })
+ Queue.#instances.push(this)
+ }
+
+ async add (headers: Headers | null, data?: Data): Promise<any> {
+ return await this.#assign(task => this.#queue.push(task), headers, data)
+ }
+
+ async prioritize (headers: Headers | null, data?: Data): Promise<any> {
+ return await this.#assign(task => this.#queue.unshift(task), headers, data)
+ }
+
+ terminate (): void {
+ this.#job = undefined
+ this.#worker.terminate()
+ }
+
+ async #assign (enqueue: (task: Task) => number, headers: Headers | null, data?: Data) {
+ return new Promise(async (resolve, reject): Promise<void> => {
+ const task: Task = {
+ id: performance.now(),
+ headers,
+ data,
+ resolve,
+ reject
+ }
+ await enqueue(task)
+ debugger
+ if (this.#isIdle) this.#process()
+ })
+ }
+
+ #process = (): void => {
+ debugger
+ this.#job = this.#queue.shift()
+ if (this.#job == null) {
+ throw new Error('Failed to get job from empty task queue.')
+ }
+ const { id, headers, data, reject } = this.#job
+ this.#isIdle = !id
+ try {
+ const buffers: ArrayBuffer[] = []
+ if (data != null) {
+ for (let d of Object.keys(data)) {
+ buffers.push(data[d])
+ }
+ }
+ this.#worker.postMessage({ headers, data }, buffers)
+ } catch (err) {
+ reject(err)
+ }
+ }
+
+ #report (results: any[]): void {
+ if (this.#job == null) {
+ throw new Error('Worker returned results but had nowhere to report it.')
+ }
+ const { resolve, reject } = this.#job
+ debugger
+ try {
+ resolve(results)
+ } catch (err) {
+ reject(err)
+ } finally {
+ this.#process()
+ }
+ }
+}
+
+/**
+* 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 Pow = ${Pow}
+* `
+* ```
+* 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 {
+ /**
+ * 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 {Header} headers - Flat object of header data
+ * @param {any[]} data - Transferred buffer of data to process
+ * @returns Promise for processed data
+ */
+ static async work (headers: Headers | null, data?: Data): Promise<any> {
+ return new Promise(async (resolve, reject): Promise<void> => {
+ try {
+ let x, y
+ if (headers != null) {
+ const { sample } = headers
+ x = sample
+ }
+ if (data != null) {
+ const { buf } = data
+ y = buf
+ }
+ resolve({ x, y })
+ } catch (err) {
+ reject(err)
+ }
+ })
+ }
+
+ /**
+ * Encodes worker results as an ArrayBuffer so it can be transferred back to
+ * the main thread.
+ *
+ * @param {any[]} results - Array of processed data
+ */
+ static report (results: any[]): void {
+ const buffer = new TextEncoder().encode(JSON.stringify(results)).buffer
+ //@ts-expect-error
+ postMessage(buffer, [buffer])
+ }
+
+ /**
+ * Listens for messages from the main thread.
+ *
+ * Extending classes must call this in a static initialization block:
+ * ```
+ * static {
+ * Extension.listen()
+ * }
+ * ```
+ */
+ static listen (): void {
+ addEventListener('message', (message: any): void => {
+ const { name, headers, data } = message
+ if (name === 'STOP') {
+ close()
+ const buffer = new ArrayBuffer(0)
+ //@ts-expect-error
+ postMessage(buffer, [buffer])
+ } else {
+ this.work(headers, data).then(this.report).catch(this.report)
+ }
+ })
+ }
+}
\r
'use strict'\r
\r
+import { Data, Headers, WorkerInterface } from '.'\r
import { Blake2b } from '#src/lib/blake2b.js'\r
-import { Data, Headers, WorkerInterface } from '#src/lib/pool.js'\r
\r
// Ported in 2014 by Dmitry Chestnykh and Devi Mandiri.\r
// Public domain.\r
'use strict'
+import { Data, Headers, WorkerInterface } from '.'
import { bytes, hex, utf8, default as Convert } from '#src/lib/convert.js'
import { Entropy } from '#src/lib/entropy.js'
-import { Data, Headers, WorkerInterface } from '#src/lib/pool.js'
type SafeRecord = {
encrypted: string,