//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
-import { Worker as NodeWorker } from 'node:worker_threads'
+import { Worker as NodeWorker, threadId } from 'node:worker_threads'
//@ts-expect-error
import nano25519_wasm from '../../build/nano25519.wasm'
type Data = {
+ url: string
+ id: string
action: string
message?: string | ArrayBuffer
privateKey?: string
function handleMessage (message: unknown): void {
NODE: if (host == null) setTimeout(() => handleMessage(message), 0)
let result: undefined | boolean | string | Uint8Array<ArrayBuffer>
+ let url: undefined | string
+ let id: undefined | string
try {
if (message == null
|| typeof message !== 'object'
|| !('data' in message)
|| message.data == null
|| typeof message.data !== 'object'
+ || !('url' in message.data)
+ || typeof message.data.url !== 'string'
+ || !('id' in message.data)
+ || typeof message.data.id !== 'string'
|| !('action' in message.data)
|| typeof message.data.action !== 'string'
) {
throw new TypeError('Invalid nano25519Worker request')
}
- const data: Data = message.data as object & Record<"action", string>
+ const data: Data = message.data as object & { url: string, id: string, action: string }
+ url = data.url
+ id = data.id
+ if (typeof url !== 'string' || typeof id !== 'string') return
+ BROWSER: if (url !== location.href) return
+ NODE: if (url !== threadId.toString()) return
+
if (data.action === 'start') {
isListening = true
result = 'started'
result = JSON.stringify(err)
}
} finally {
- BROWSER: postMessage(result)
- NODE: host?.postMessage({ data: result })
+ BROWSER: postMessage({ url, id, result })
+ NODE: host?.postMessage({ data: { url, id, result } })
}
}
BROWSER: addEventListener('message', handleMessage)
// Create worker module
function init (): void {
try {
- url = URL.createObjectURL(new Blob([nano25519_worker], { type: 'text/javascript' }))
+ BROWSER: url = URL.createObjectURL(new Blob([nano25519_worker], { type: 'text/javascript' }))
BROWSER: worker = new Worker(url, { type: 'module' })
NODE: worker = new NodeWorker(nano25519_worker, {
eval: true,
stderr: false,
stdout: false
})
+ NODE: url = worker.threadId.toString()
console.log(`nano25519 initialized.`)
isWorkerReady = true
} catch (err) {
if (!isWorkerReady) init()
if (!isWorkerListening) {
return new Promise(async (resolve, reject): Promise<void> => {
- const onstarted = (msg: any): void => {
- const result = msg.data
+ const onstarted = (msg: { data: Record<string, unknown> }): void => {
+ const { data } = msg
+ if (data.url !== url) return
+ const { result } = data
if (result === 'started') {
console.log('worker started successfully')
isWorkerListening = true
- resolve(result)
+ resolve()
} else {
- reject(result)
+ isWorkerListening = false
+ reject()
}
}
//@ts-expect-error
//@ts-expect-error
NODE: worker.on('message', onstarted)
console.log(`starting worker`)
- BROWSER: worker.postMessage({ action: 'start' })
- NODE: worker.postMessage({ data: { action: 'start' } })
+ const id = crypto.randomUUID()
+ BROWSER: worker.postMessage({ url, id, action: 'start' })
+ NODE: worker.postMessage({ data: { url, id, action: 'start' } })
})
}
}
transfer.push(data[k])
}
}
- const onresult = (msg: Record<"data", unknown>): void => {
- const result = msg.data
+ const onresult = (msg: { data: Record<string, unknown> }): void => {
+ const { data } = msg
+ if (data.url !== url) return
+ const { result } = data
console.log(`received result from worker: `, result)
if (typeof result !== 'boolean' && typeof result !== 'string' && !isBytes(result)) {
return reject('Invalid return type')
//@ts-expect-error
NODE: worker.on('message', onresult)
console.log(`sending data to worker: `, data)
+ data.url = url
+ data.id = crypto.randomUUID()
BROWSER: worker.postMessage(data, transfer)
NODE: worker.postMessage({ data }, transfer)
})
// Request that the worker stop listening without terminating
async function stop (): Promise<void> {
return new Promise((resolve, reject): void => {
- const onstop = (msg: any): void => {
- const result = msg.data
+ const onstop = (msg: { data: Record<string, unknown> }): void => {
+ const { data } = msg
+ if (data.url !== url) return
+ const { result } = data
if (result === 'stopped') {
console.log('worker stopped successfully')
isWorkerListening = false
//@ts-expect-error
NODE: worker.on('message', onstop)
console.log(`stopping worker`)
- BROWSER: worker.postMessage({ action: 'stop' })
- NODE: worker.postMessage({ data: { action: 'stop' } })
+ const id = crypto.randomUUID()
+ BROWSER: worker.postMessage({ url, id, action: 'stop' })
+ NODE: worker.postMessage({ data: { url, id, action: 'stop' } })
})
}