]> git.codecow.com Git - libnemo.git/commitdiff
Remove unused job property and 10 second vault request timeout to support UX.
authorChris Duncan <chris@codecow.com>
Thu, 6 Aug 2026 05:42:41 +0000 (22:42 -0700)
committerChris Duncan <chris@codecow.com>
Thu, 6 Aug 2026 05:42:41 +0000 (22:42 -0700)
src/lib/vault/index.ts

index e45b70dbf28b267840965fa8e64d1d9a416a9eee..5d19bd4e31ea96e131ee8d3d8c5143469f25953b 100644 (file)
@@ -15,6 +15,7 @@ type Task = {
        data: TaskData
        reject: (value: any) => void
        resolve: (value: any) => void
+       timeout: number | NodeJS.Timeout
 }
 
 //@ts-expect-error
@@ -25,7 +26,6 @@ const TERMINATED = 'Worker terminated'
 
 export class Vault {
        #eventTarget: EventTarget = new EventTarget()
-       #job?: Task
        #isLocked: boolean = true
        #isTerminated: boolean = false
        #tasks: Map<string, Task> = new Map<string, Task>()
@@ -44,7 +44,8 @@ export class Vault {
                BROWSER: {
                        this.#url = URL.createObjectURL(new Blob([vaultWorker], { type: 'text/javascript' }))
                        this.#worker = new Worker(this.#url, { type: 'module' })
-                       this.#worker.addEventListener('message', listener)
+                       this.#worker.addEventListener('message', this.#report)
+                       this.#worker.addEventListener('error', this.terminate)
                }
                NODE: {
                        this.#worker = new NodeWorker(vaultWorker, {
@@ -59,7 +60,7 @@ export class Vault {
 
        get isLocked (): boolean { return this.#isLocked }
 
-       request<T extends Data | Record<string, Data>> (payload: Record<string, Data | Record<string, Data>>): Promise<Record<string, T>> {
+       request<T extends Data | Record<string, Data>> (payload: Record<string, Data | Record<string, Data>> & Record<'action', string>): Promise<Record<string, T>> {
                if (this.#isTerminated) {
                        throw new Error(TERMINATED)
                }
@@ -76,17 +77,26 @@ export class Vault {
                        taskId
                }
                return new Promise((resolve, reject): void => {
+                       const timeout = setTimeout(() => {
+                               this.#tasks.delete(taskId)
+                               reject(new Error('Vault request timed out', { cause: payload.action }))
+                       }, 10_000)
                        const task: Task = {
                                data,
                                resolve,
-                               reject
+                               reject,
+                               timeout
                        }
                        this.#tasks.set(taskId, task)
                        try {
                                BROWSER: this.#worker.postMessage(data, buffers)
                                NODE: this.#worker.postMessage({ data }, buffers)
                        } catch (err) {
+                               clearTimeout(timeout)
                                this.#tasks.delete(taskId)
+                               for (const buffer of buffers) {
+                                       new Uint8Array(buffer).fill(0)
+                               }
                                reject(err)
                        }
                })
@@ -98,20 +108,20 @@ export class Vault {
                BROWSER: URL.revokeObjectURL(this.#url)
                //@ts-expect-error
                NODE: this.#worker.unref()
-               this.#job?.reject(TERMINATED)
-               this.#job = undefined
                for (const [_, task] of this.#tasks) {
                        task?.reject?.(TERMINATED)
                }
                this.#tasks.clear()
        }
 
-       #report (results: unknown): void {
-               if (results == null) return
-               const { taskUrl, taskId, error, isLocked } = results as Record<string, unknown>
+       #report (message: unknown): void {
+               if (message == null || typeof message !== 'object') return
+               if (!('data' in message) || message.data == null || typeof message !== 'object') return
+               const results = message.data as Record<string, unknown>
+               const { taskUrl, taskId, error, isLocked } = results
                if (taskUrl === this.#url) {
                        if (typeof taskId !== 'string') {
-                               throw new Error('Vault worker job invalid ID')
+                               throw new Error('Vault worker job invalid ID', { cause: typeof taskId })
                        }
                        if (typeof isLocked === 'boolean' && this.#isLocked !== isLocked) {
                                this.#isLocked = isLocked
@@ -125,7 +135,7 @@ export class Vault {
                        }
                        const { resolve, reject } = task
                        if (error != null) {
-                               reject(results)
+                               reject(new Error(String(error)))
                        } else {
                                resolve(results)
                        }