import type { FleetServer } from '../fleet-overview.js'; import type { RuntimeAction } from '../provisioning.js'; import { applicableRuntimeActions } from './lifecycle-actions.js'; export const fleetActions = ['restart', 'start', 'stop', 'rebuild', 'destroy'] as const; export type FleetAction = RuntimeAction | 'destroy'; export interface FleetActionFailure { server: string; error: string; } export interface FleetActionResult { queued: { server: string; deploymentId: string }[]; failed: FleetActionFailure[]; } export function fleetActionAvailable( server: FleetServer, action: FleetAction, now: number ): boolean { return action === 'destroy' || applicableRuntimeActions(server, now).includes(action); } /** Submit only the reviewed selection. Each server keeps its own durable job and result. */ export async function queueFleetAction( action: FleetAction, servers: readonly string[], request: typeof fetch = fetch ): Promise { const result: FleetActionResult = { queued: [], failed: [] }; for (const server of new Set(servers)) { try { const response = action === 'destroy' ? await request(`/api/servers/${encodeURIComponent(server)}`, { method: 'DELETE' }) : await request('/api/provisioning', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ server, action }) }); const body = await response.json(); if (!response.ok || !body.deploymentId) { result.failed.push({ server, error: body.error ?? 'Could not queue this operation.' }); } else result.queued.push({ server, deploymentId: body.deploymentId }); } catch { result.failed.push({ server, error: 'Could not confirm whether the request was queued. Check Provisioning before trying again.' }); } } return result; }