import { parentPort } from 'electron'; import { prepareProjectReleaseSummary, ProjectReleaseBuildError, type ReleaseBuildRuntimeContext, } from './project-release-builder'; type StartMessage = { type: 'start'; jobId: string; projectPath: string; clientVersion: string; runtimeContext: ReleaseBuildRuntimeContext; }; type CancelMessage = { type: 'cancel'; jobId: string; }; type WorkerMessage = StartMessage | CancelMessage; const controllers = new Map(); function readMessage(value: unknown): WorkerMessage | null { const candidate = value && typeof value === 'object' && 'data' in value ? (value as { data?: unknown }).data : value; if (!candidate || typeof candidate !== 'object') return null; const message = candidate as Partial; if (message.type !== 'start' && message.type !== 'cancel') return null; return message as WorkerMessage; } function post(message: unknown): void { parentPort?.postMessage(message); } async function run(message: StartMessage): Promise { const controller = new AbortController(); controllers.set(message.jobId, controller); try { const prepared = await prepareProjectReleaseSummary({ projectPath: message.projectPath, clientVersion: message.clientVersion, runtimeContext: message.runtimeContext, signal: controller.signal, onProgress: (progress) => post({ type: 'progress', jobId: message.jobId, progress }), }); try { if (controller.signal.aborted) { throw new ProjectReleaseBuildError('LOCAL_BUILD_CANCELLED'); } post({ type: 'complete', jobId: message.jobId, packageSummary: prepared.sourceArchive.summary, contract: prepared.contract, }); } finally { await prepared.dispose(); } } catch (error) { const code = error instanceof ProjectReleaseBuildError ? error.code : 'LOCAL_BUILD_FAILED'; post({ type: 'error', jobId: message.jobId, code, message: error instanceof Error ? error.message : String(error), }); } finally { controllers.delete(message.jobId); // The worker is single-job by design. Exiting here releases any native // module state and makes the process count observable and bounded. setImmediate(() => process.exit(0)); } } parentPort?.on('message', (value) => { const message = readMessage(value); if (!message) return; if (message.type === 'cancel') { controllers.get(message.jobId)?.abort(); return; } if (controllers.has(message.jobId)) return; void run(message); });