import { implement } from "@orpc/server"; import { api, type RestartingProcessInfo, type CronProcessInfo, type TaskEntryInfo, type ManagerStatus, } from "./contract.ts"; import type { Manager } from "../manager.ts"; import type { RestartingProcess } from "../restarting-process.ts"; import type { CronProcess } from "../cron-process.ts"; const os = implement(api).$context<{ manager: Manager }>(); // Helper to serialize a RestartingProcess to API response function serializeProcess(proc: RestartingProcess): RestartingProcessInfo { return { name: proc.name, state: proc.state, restarts: proc.restarts, }; } // Helper to serialize a CronProcess to API response function serializeCron(cron: CronProcess): CronProcessInfo { return { name: cron.name, state: cron.state, runCount: cron.runCount, failCount: cron.failCount, nextRun: cron.nextRun?.toISOString() ?? null, }; } // Manager handlers const managerStatus = os.manager.status.handler(async ({ context }): Promise => { const manager = context.manager; const taskList = manager.getTaskList(); return { state: manager.state, processCount: manager.getRestartingProcesses().size, cronCount: manager.getCronProcesses().size, taskCount: taskList?.tasks.length ?? 0, }; }); // Processes handlers const getProcess = os.processes.get.handler(async ({ input, context }) => { const proc = context.manager.getProcessByTarget(input.target); if (!proc) { throw new Error(`Process not found: ${input.target}`); } return serializeProcess(proc); }); const listProcesses = os.processes.list.handler(async ({ context }) => { const processes = Array.from(context.manager.getRestartingProcesses().values()); return processes.map(serializeProcess); }); const addProcess = os.processes.add.handler(async ({ input, context }) => { const proc = context.manager.addProcess(input.name, input.definition); return serializeProcess(proc); }); const startProcess = os.processes.start.handler(async ({ input, context }) => { const proc = context.manager.startProcessByTarget(input.target); return serializeProcess(proc); }); const stopProcess = os.processes.stop.handler(async ({ input, context }) => { const proc = await context.manager.stopProcessByTarget(input.target); return serializeProcess(proc); }); const restartProcess = os.processes.restart.handler(async ({ input, context }) => { const proc = await context.manager.restartProcessByTarget(input.target, input.force); return serializeProcess(proc); }); const reloadProcess = os.processes.reload.handler(async ({ input, context }) => { const proc = await context.manager.reloadProcessByTarget(input.target, input.definition, { restartImmediately: input.restartImmediately, }); return serializeProcess(proc); }); const removeProcess = os.processes.remove.handler(async ({ input, context }) => { await context.manager.removeProcessByTarget(input.target); return { success: true }; }); // Crons handlers const getCron = os.crons.get.handler(async ({ input, context }) => { const cron = context.manager.getCronByTarget(input.target); if (!cron) { throw new Error(`Cron not found: ${input.target}`); } return serializeCron(cron); }); const listCrons = os.crons.list.handler(async ({ context }) => { const crons = Array.from(context.manager.getCronProcesses().values()); return crons.map(serializeCron); }); const triggerCron = os.crons.trigger.handler(async ({ input, context }) => { const cron = await context.manager.triggerCronByTarget(input.target); return serializeCron(cron); }); const startCron = os.crons.start.handler(async ({ input, context }) => { const cron = context.manager.startCronByTarget(input.target); return serializeCron(cron); }); const stopCron = os.crons.stop.handler(async ({ input, context }) => { const cron = await context.manager.stopCronByTarget(input.target); return serializeCron(cron); }); // Tasks handlers const getTask = os.tasks.get.handler(async ({ input, context }) => { const task = context.manager.getTaskByTarget(input.target); if (!task) { throw new Error(`Task not found: ${input.target}`); } return task as TaskEntryInfo; }); const listTasks = os.tasks.list.handler(async ({ context }) => { const taskList = context.manager.getTaskList(); if (!taskList) { return []; } return taskList.tasks.map((t) => ({ id: t.id, state: t.state, processNames: t.processes.map((p) => p.name), })) as TaskEntryInfo[]; }); const addTask = os.tasks.add.handler(async ({ input, context }) => { const task = context.manager.addTask(input.name, input.definition); return task as TaskEntryInfo; }); const removeTask = os.tasks.remove.handler(async ({ input, context }) => { const task = context.manager.removeTaskByTarget(input.target); return task as TaskEntryInfo; }); export const router = os.router({ manager: { status: managerStatus, }, processes: { add: addProcess, get: getProcess, list: listProcesses, start: startProcess, stop: stopProcess, restart: restartProcess, reload: reloadProcess, remove: removeProcess, }, crons: { get: getCron, list: listCrons, trigger: triggerCron, start: startCron, stop: stopCron, }, tasks: { get: getTask, list: listTasks, add: addTask, remove: removeTask, }, });