{"version":3,"file":"index-chunk2.mjs","sources":["../../src/threads/index.ts"],"sourcesContent":["import type { WorkerOptions } from 'node:worker_threads';\nimport { Worker, isMainThread, parentPort, SHARE_ENV } from 'node:worker_threads';\n\nconst port = parentPort!;\nif (!isMainThread && !port) {\n  throw new ReferenceError('Failed to receive parent message port');\n}\n\nconst enum MainMessageCodes {\n  Start = 'START',\n  Close = 'CLOSE',\n  Pull = 'PULL',\n}\n\ninterface MainMessage {\n  id?: number;\n  kind: MainMessageCodes;\n  data?: any;\n}\n\nconst enum ThreadMessageCodes {\n  Next = 'NEXT',\n  Throw = 'THROW',\n  Return = 'RETURN',\n}\n\ninterface ThreadMessage {\n  id?: number;\n  kind: ThreadMessageCodes;\n  data?: any;\n  extra?: Record<string, unknown>;\n}\n\nconst workerOpts: WorkerOptions = {\n  env: SHARE_ENV,\n  stderr: false,\n  stdout: false,\n  stdin: false,\n};\n\nconst getMessageData = (message: ThreadMessage) => {\n  const data = message.data;\n  if (message.kind === ThreadMessageCodes.Throw) {\n    return typeof data === 'object' && data && message.extra != null\n      ? Object.assign(data, message.extra)\n      : data;\n  } else {\n    return data;\n  }\n};\n\nconst asyncIteratorSymbol = (): typeof Symbol.asyncIterator =>\n  (typeof Symbol === 'function' && Symbol.asyncIterator) || ('@@asyncIterator' as any);\n\n/** Capture the stack above the caller */\nfunction captureStack(): NodeJS.CallSite[] {\n  const _error: any = new Error();\n  const _prepareStackTrace = Error.prepareStackTrace;\n  try {\n    let stack: NodeJS.CallSite[] | undefined;\n    Error.prepareStackTrace = (_error, _stack) => (stack = _stack);\n    Error.captureStackTrace(_error);\n    if (!_error.stack) throw _error;\n    return (stack && stack.slice(2)) || [];\n  } finally {\n    Error.prepareStackTrace = _prepareStackTrace;\n  }\n}\n\nexport interface Generator<Args extends readonly any[], Next> {\n  // TODO: Update to support for AsyncGenerator interface\n  (...args: Args): AsyncIterableIterator<Next>;\n}\n\nfunction main<Args extends readonly any[], Next>(url: string | URL): Generator<Args, Next> {\n  let worker: Worker | undefined;\n  let activeCalls = 0;\n  let ids = 0;\n  return (...args: Args) => {\n    if (!worker) {\n      worker = new Worker(url, workerOpts);\n      worker.unref();\n    }\n\n    const currentWorker = worker;\n    const id = ++ids | 0;\n    const buffer: ThreadMessage[] = [];\n\n    let started = false;\n    let ended = false;\n    let pulled = false;\n    let resolve: ((value: IteratorResult<Next>) => void) | void;\n    let reject: ((error: any) => void) | void;\n\n    function cleanup() {\n      if (ended) return;\n      ended = true;\n      resolve = undefined;\n      reject = undefined;\n      currentWorker.removeListener('message', receiveMessage);\n      currentWorker.removeListener('error', receiveError);\n      currentWorker.removeListener('exit', receiveExit);\n      if (--activeCalls === 0) currentWorker.unref();\n    }\n\n    function sendMessage(kind: MainMessageCodes) {\n      currentWorker.postMessage({ id, kind });\n    }\n\n    function fail(error: any) {\n      const pendingReject = reject;\n      cleanup();\n      if (pendingReject) {\n        pendingReject(error);\n      } else {\n        buffer.length = 1;\n        buffer[0] = {\n          id,\n          kind: ThreadMessageCodes.Throw,\n          data: error,\n        };\n      }\n    }\n\n    function receiveError(error: any) {\n      fail(error);\n    }\n\n    function receiveExit(code: number) {\n      if (ended) return;\n      if (worker === currentWorker) worker = undefined;\n      fail(new Error(`Worker stopped unexpectedly with exit code ${code}`));\n    }\n\n    function receiveMessage(data: unknown) {\n      const message: ThreadMessage | null =\n        data && typeof data === 'object' && 'kind' in data ? (data as ThreadMessage) : null;\n      if (!message) {\n        return;\n      } else if (reject && message.kind === ThreadMessageCodes.Throw) {\n        reject(getMessageData(message));\n        cleanup();\n      } else if (resolve && message.kind === ThreadMessageCodes.Return) {\n        resolve({ done: true, value: getMessageData(message) });\n        cleanup();\n      } else if (resolve && message.kind === ThreadMessageCodes.Next) {\n        pulled = false;\n        resolve({ done: false, value: getMessageData(message) });\n      } else if (\n        message.kind === ThreadMessageCodes.Throw ||\n        message.kind === ThreadMessageCodes.Return\n      ) {\n        buffer.push(message);\n        cleanup();\n      } else if (message.kind === ThreadMessageCodes.Next) {\n        buffer.push(message);\n        pulled = false;\n      }\n    }\n\n    return {\n      async next() {\n        if (!started) {\n          started = true;\n          if (activeCalls++ === 0) currentWorker.ref();\n          currentWorker.addListener('message', receiveMessage);\n          currentWorker.addListener('error', receiveError);\n          currentWorker.addListener('exit', receiveExit);\n          currentWorker.postMessage({\n            id,\n            kind: MainMessageCodes.Start,\n            data: args,\n          });\n        }\n        if (ended && !buffer.length) {\n          return { done: true } as IteratorReturnResult<any>;\n        } else if (!ended && !pulled && buffer.length <= 1) {\n          pulled = true;\n          sendMessage(MainMessageCodes.Pull);\n        }\n        const message = buffer.shift();\n        if (message && message.kind === ThreadMessageCodes.Throw) {\n          cleanup();\n          throw getMessageData(message);\n        } else if (message && message.kind === ThreadMessageCodes.Return) {\n          cleanup();\n          return { value: getMessageData(message), done: true };\n        } else if (message && message.kind === ThreadMessageCodes.Next) {\n          return { value: getMessageData(message), done: false };\n        } else {\n          return new Promise((_resolve, _reject) => {\n            resolve = (value) => {\n              resolve = undefined;\n              reject = undefined;\n              _resolve(value);\n            };\n            reject = (error) => {\n              resolve = undefined;\n              reject = undefined;\n              _reject(error);\n            };\n          });\n        }\n      },\n      async return() {\n        if (!ended) {\n          cleanup();\n          sendMessage(MainMessageCodes.Close);\n        }\n        return { done: true } as IteratorReturnResult<any>;\n      },\n      [asyncIteratorSymbol()]() {\n        return this;\n      },\n    };\n  };\n}\n\nfunction thread<Args extends readonly any[], Next>(\n  message: MainMessage,\n  generator: Generator<Args, Next>\n): void {\n  if (message.kind !== MainMessageCodes.Start) return;\n  const id = message.id;\n  const iterator = generator(...(message.data as any));\n\n  let ended = false;\n  let pulled = false;\n  let looping = false;\n\n  function cleanup() {\n    ended = true;\n    port.removeListener('message', receiveMessage);\n  }\n\n  async function sendMessage(kind: ThreadMessageCodes, data?: any) {\n    try {\n      const message: ThreadMessage = { id, kind, data };\n      // NOTE: Copy error annotations to separate property\n      if (kind === ThreadMessageCodes.Throw && typeof data === 'object' && data != null)\n        message.extra = { ...data };\n      port.postMessage(message);\n    } catch (error) {\n      cleanup();\n      if (iterator.throw) {\n        let result = await iterator.throw();\n        if (result.done === false && iterator.return) {\n          result = await iterator.return();\n          sendMessage(ThreadMessageCodes.Return, result.value);\n        } else {\n          sendMessage(ThreadMessageCodes.Return, result.value);\n        }\n      } else {\n        sendMessage(ThreadMessageCodes.Return);\n      }\n    }\n  }\n\n  async function receiveMessage(data: unknown) {\n    const message: MainMessage | null =\n      data && typeof data === 'object' && 'kind' in data ? (data as MainMessage) : null;\n    let next: IteratorResult<Next>;\n    if (!message) {\n      return;\n    } else if (message.kind === MainMessageCodes.Close) {\n      cleanup();\n      if (iterator.return) iterator.return();\n    } else if (message.kind === MainMessageCodes.Pull && looping) {\n      pulled = true;\n    } else if (message.kind === MainMessageCodes.Pull) {\n      for (pulled = looping = true; pulled && !ended; ) {\n        try {\n          if ((next = await iterator.next()).done) {\n            cleanup();\n            if (iterator.return) next = await iterator.return();\n            sendMessage(ThreadMessageCodes.Return, next.value);\n          } else {\n            pulled = false;\n            sendMessage(ThreadMessageCodes.Next, next.value);\n          }\n        } catch (error) {\n          cleanup();\n          sendMessage(ThreadMessageCodes.Throw, error);\n        }\n      }\n      looping = false;\n    }\n  }\n\n  port.addListener('message', receiveMessage);\n}\n\nexport function expose<Args extends readonly any[], Return>(\n  generator: Generator<Args, Return>\n): Generator<Args, Return> {\n  if (isMainThread) {\n    const call = captureStack()[0];\n    const file = call && call.getFileName();\n    if (!file) throw new ReferenceError('Captured stack trace is empty');\n    const url = file.startsWith('file://') ? new URL(file) : file;\n    return main(url);\n  } else {\n    port.addListener('message', (data) => {\n      const message: MainMessage | null =\n        data && typeof data === 'object' && 'kind' in data ? (data as MainMessage) : null;\n      if (message) thread(message, generator);\n    });\n    return generator;\n  }\n}\n"],"names":["port","parentPort","isMainThread","ReferenceError","MainMessageCodes","ThreadMessageCodes","workerOpts","env","SHARE_ENV","stderr","stdout","stdin","getMessageData","message","data","kind","Throw","extra","Object","assign","asyncIteratorSymbol","Symbol","asyncIterator","expose","generator","call","captureStack","_error","Error","_prepareStackTrace","prepareStackTrace","stack","_stack","captureStackTrace","slice","file","getFileName","main","url","worker","activeCalls","ids","args","Worker","unref","currentWorker","id","buffer","started","ended","pulled","resolve","reject","cleanup","undefined","removeListener","receiveMessage","receiveError","receiveExit","sendMessage","postMessage","fail","error","pendingReject","length","code","Return","done","value","Next","push","next","ref","addListener","Start","Pull","shift","Promise","_resolve","_reject","return","Close","this","startsWith","URL","thread","iterator","looping","async","throw","result"],"mappings":"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"}