import { clean, machinesGet, machinesListForApp, machinesListForOrg, machinesRequest, mutationPreview, resolveOrganizationSlug, summarizeMachine, } from './fly-core.ts' import type { FlyMachineMutationInput, FlyMachinesInput } from './types.ts' /** * Start a Fly Machine. Pass `dryRun: true` to preview without contacting Fly. */ export async function startMachine(params: FlyMachineMutationInput = {}) { const { appName, machineId } = mutationTarget(params) const path = machinePath(appName, machineId, '/start') const preview = mutationPreview(params, { action: 'start machine ' + machineId + ' on ' + appName, method: 'POST', path, }) if (preview) return preview const result = await machinesRequest(path, { ...params, method: 'POST' }) return { ok: true, action: 'start', appName, machineId, result } } /** * Stop a Fly Machine. Pass `dryRun: true` to preview without contacting Fly. */ export async function stopMachine(params: FlyMachineMutationInput = {}) { const { appName, machineId } = mutationTarget(params) const path = machinePath(appName, machineId, '/stop') const body: Record = {} if (params.timeout != null) body.timeout = params.timeout if (clean(params.signal)) body.signal = clean(params.signal) const hasBody = Object.keys(body).length > 0 const preview = mutationPreview(params, { action: 'stop machine ' + machineId + ' on ' + appName, method: 'POST', path, body: hasBody ? body : undefined, }) if (preview) return preview const result = await machinesRequest(path, { ...params, method: 'POST', body: hasBody ? body : undefined, }) return { ok: true, action: 'stop', appName, machineId, result } } /** * Destroy a Fly Machine. Requires `confirm: true`. Pass `dryRun: true` to preview. * Never call this from a smoke test or scheduled job. */ export async function destroyMachine(params: FlyMachineMutationInput = {}) { const { appName, machineId } = mutationTarget(params) const path = machinePath(appName, machineId) const query = params.force === true ? { force: true } : undefined const preview = mutationPreview(params, { action: 'destroy machine ' + machineId + ' on ' + appName, method: 'DELETE', path, query, requireConfirm: true, }) if (preview) return preview const result = await machinesRequest(path, { ...params, method: 'DELETE', query }) return { ok: true, action: 'destroy', appName, machineId, result } } /** * List Fly machines via Machines REST (org-wide or by `appName`), optionally filtered by `state`. * @returns Machine count and summarized machine records. * @param params - Organization/app filters for this Fly helper. * @example * import machines from 'kody:@kody/fly/machines' * const result = await machines({ organizationSlug: 'my-org', state: 'started' }) * // => { count: 5, machines: [...] } */ export default async function machines(params: FlyMachinesInput & FlyMachineMutationInput = {}) { if (params.machineId || params.id) { return await getMachine(params) } return await listMachines(params) } export async function listMachines(params: FlyMachinesInput = {}) { const appName = String(params.appName || params.app || '').trim() const appId = String(params.appId || '').trim() const state = String(params.state || '').trim() || undefined if (appName) { const machines = await machinesListForApp(appName, { ...params, state }) const summarized = machines.map((machine: any) => summarizeMachine(machine, { name: appName })) return { count: summarized.length, appName, machines: summarized } } if (appId && !appName) { const orgResult = await machinesListForOrg({ ...params, state }) const machines = orgResult.machines .filter((machine: any) => machine?.app?.id === appId || machine?.app_id === appId) .map((machine: any) => summarizeMachine(machine)) return { count: machines.length, organization: orgResult.organization, machines, } } const orgResult = await machinesListForOrg({ ...params, state }) const machines = orgResult.machines.map((machine: any) => summarizeMachine(machine)) return { count: machines.length, organization: orgResult.organization, orgSlug: orgResult.organization.slug, machines, } } export async function getMachine(params: FlyMachinesInput = {}) { const appName = String(params.appName || params.app || '').trim() const machineId = String(params.machineId || params.id || '').trim() if (!appName) throw new Error('appName is required.') if (!machineId) throw new Error('machineId is required.') const machine = await machinesGet(appName, machineId, params) return { machine: summarizeMachine(machine, { name: appName }), raw: machine, } } function mutationTarget(params: FlyMachineMutationInput) { const appName = clean(params.appName || params.app) const machineId = clean(params.machineId || params.id) if (!appName) throw new Error('appName is required.') if (!machineId) throw new Error('machineId is required.') return { appName, machineId } } function machinePath(appName: string, machineId: string, suffix = '') { return ( '/apps/' + encodeURIComponent(appName) + '/machines/' + encodeURIComponent(machineId) + suffix ) } export { resolveOrganizationSlug }