/// import type { CounterfactualAnalysis, LeavePlacement, PlanOutcome, PlanningExplanation, PlanningOutcome, PlanningReason, PlanningSnapshot, PlanningStateSnapshot, } from './leave-planner.service'; import { analyzeCounterfactualInternal, calculatePlanningAsyncInternal, explainIncompleteCheckpoint, type PlanningArtifacts, } from './leave-planner.core'; type WorkerPlanningRequest = { calculationDate?: string; declaredDays?: unknown; horizon?: { start?: unknown; end?: unknown }; balances?: unknown; rules?: unknown; identities?: unknown; labels?: unknown; deadlineMs?: unknown; progress?: unknown; }; type WorkerRequest = | { type: 'plan'; request: WorkerPlanningRequest; } | { type: 'cancel' } | { type: 'counterfactual'; request: PlanningSnapshot; plan: PlanOutcome; placement: LeavePlacement; state?: PlanningStateSnapshot; } | { type: 'explain-checkpoint'; request: PlanningSnapshot; plan: PlanOutcome; state: PlanningStateSnapshot; interruption: PlanningReason; }; type WorkerResponse = | { type: 'heartbeat' } | { type: 'progress'; stage: string } | { type: 'checkpoint'; plan: PlanOutcome; state?: PlanningStateSnapshot } | { type: 'result'; outcome: PlanningOutcome } | { type: 'artifacts'; artifacts: PlanningArtifacts } | { type: 'explanation'; explanation?: PlanningExplanation; explanationError?: PlanningReason; finalState?: PlanningStateSnapshot; } | { type: 'counterfactual-result'; analysis: CounterfactualAnalysis } | { type: 'error'; code?: string; message: string }; const worker = self as DedicatedWorkerGlobalScope; let activeCalculation: { cancelled: boolean } | undefined; worker.onmessage = async (event: MessageEvent) => { try { if (event.data?.type === 'cancel') { if (activeCalculation) activeCalculation.cancelled = true; return; } if (event.data?.type === 'plan') { const calculation = { cancelled: false }; activeCalculation = calculation; let artifacts: PlanningArtifacts = {}; let outcomePosted = false; let outcome: PlanningOutcome; // The cooperative driver yields during preparation and search, even within one phase. const heartbeat = () => worker.postMessage({ type: 'heartbeat' } satisfies WorkerResponse); const heartbeatTimer = setInterval(heartbeat, 1000); try { heartbeat(); outcome = await calculatePlanningAsyncInternal( { ...event.data.request, progress: (stage: string) => worker.postMessage({ type: 'progress', stage, } satisfies WorkerResponse), }, (plan, state) => worker.postMessage({ type: 'checkpoint', plan, state, } satisfies WorkerResponse), (value) => (artifacts = value), (value) => { outcomePosted = true; worker.postMessage({ type: 'result', outcome: value, } satisfies WorkerResponse); }, (explanation, explanationError, finalState) => worker.postMessage({ type: 'explanation', explanation, explanationError, finalState, } satisfies WorkerResponse), () => calculation.cancelled, ); } catch (error) { worker.postMessage({ type: 'error', code: 'planner-error', message: error instanceof Error ? error.message : String(error), } satisfies WorkerResponse); return; } finally { clearInterval(heartbeatTimer); if (activeCalculation === calculation) activeCalculation = undefined; } if (!outcomePosted) worker.postMessage({ type: 'result', outcome } satisfies WorkerResponse); worker.postMessage({ type: 'artifacts', artifacts } satisfies WorkerResponse); return; } if (event.data?.type === 'explain-checkpoint') { const result = explainIncompleteCheckpoint( event.data.request, event.data.plan, event.data.state, event.data.interruption, ); worker.postMessage({ type: 'explanation', ...result } satisfies WorkerResponse); return; } if (event.data?.type !== 'counterfactual') return; try { const analysis = analyzeCounterfactualInternal( event.data.request, event.data.plan, event.data.placement, event.data.state, ); worker.postMessage({ type: 'counterfactual-result', analysis, } satisfies WorkerResponse); } catch (error) { worker.postMessage({ type: 'error', code: 'counterfactual-error', message: error instanceof Error ? error.message : String(error), } satisfies WorkerResponse); } } catch (error) { worker.postMessage({ type: 'error', code: 'worker-error', message: error instanceof Error ? error.message : String(error), } satisfies WorkerResponse); } };