import type { AnyCircuitElement } from "circuit-json" import * as Comlink from "comlink" import type { InternalWebWorkerApi, WebWorkerConfiguration, CircuitWebWorker, } from "./shared/types" export type { CircuitWebWorker, WebWorkerConfiguration } export const createCircuitWebWorker = async ( configuration: Partial, ): Promise => { if (configuration.verbose) { console.log( "[Worker] Creating circuit web worker with config:", configuration, ) } let workerBlobUrl = configuration.webWorkerBlobUrl ?? configuration.webWorkerUrl if (!workerBlobUrl) { const cdnUrl = "https://cdn.jsdelivr.net/npm/@tscircuit/eval-webworker/dist/webworker/index.js" const workerBlob = await fetch(cdnUrl).then((res) => res.blob()) workerBlobUrl = URL.createObjectURL(workerBlob) } const rawWorker = new Worker(workerBlobUrl, { type: "module" }) const comlinkWorker = Comlink.wrap(rawWorker) if (configuration.snippetsApiBaseUrl) { await comlinkWorker.setSnippetsApiBaseUrl(configuration.snippetsApiBaseUrl) } // Create a wrapper that handles events directly through circuit instance const wrapper: CircuitWebWorker = { clearEventListeners: comlinkWorker.clearEventListeners.bind(comlinkWorker), execute: comlinkWorker.execute.bind(comlinkWorker), executeWithFsMap: comlinkWorker.executeWithFsMap.bind(comlinkWorker), renderUntilSettled: comlinkWorker.renderUntilSettled.bind(comlinkWorker), getCircuitJson: comlinkWorker.getCircuitJson.bind(comlinkWorker), on: (event: string, callback: (...args: any[]) => void) => { const proxiedCallback = Comlink.proxy(callback) comlinkWorker.on(event, proxiedCallback) }, kill: async () => { comlinkWorker[Comlink.releaseProxy]() rawWorker.terminate() }, } return wrapper }