Skip to content
← Public packages

@kentcdodds/fly

Manage Fly.io apps, Machines, logs, and metrics.

src/machines.ts

78 lines · 2.9 KB · TypeScript
import {
	machinesGet,
	machinesListForApp,
	machinesListForOrg,
	resolveOrgSlug,
	summarizeMachine,
} from './core.ts'
import type { FlyMachinesInput } from './types.ts'

/**
 * List Fly machines via Machines REST (org-wide or by `appName`), optionally filtered by `state`.
 * Pass `machineId` with `appName` to fetch one machine.
 *
 * @param params.organizationSlug - Fly org slug for org-wide listing.
 * @param params.appName - Limit to one app (or fetch one machine with `machineId`).
 * @param params.state - Optional machine state filter (e.g. `started`).
 * @param params.machineId - Optional machine id when fetching one machine.
 * @returns Machine count and summarized machine records, or `{ machine, raw }` for one machine.
 *
 * @example
 * import machines from 'kody:@kentcdodds/fly/machines'
 * const result = await machines({ organizationSlug: 'personal', state: 'started' })
 * // => { count: 5, machines: [...] }
 */
export default async function machines(params: FlyMachinesInput = {}) {
	if (params.machineId || params.id) {
		return await getMachine(params)
	}
	return await listMachines(params)
}

export async function listMachines(params = {}) {
	const appName = String(params.appName || params.app || '').trim()
	const appId = String(params.appId || '').trim()
	const state = String(params.state || '').trim() || undefined

	// Machines REST lists by app_name; org-wide list covers former GraphQL appId/global listing.
	if (appName) {
		const machines = await machinesListForApp(appName, { ...params, state })
		const summarized = machines.map((machine) => summarizeMachine(machine, { name: appName }))
		return { count: summarized.length, appName, machines: summarized }
	}

	if (appId && !appName) {
		// appId alone is not a Machines path param; resolve via org list filter by matching later callers.
		// Prefer org-wide list and filter client-side when only appId is provided.
		const orgResult = await machinesListForOrg({ ...params, state })
		const machines = orgResult.machines
			.filter((machine) => machine?.app?.id === appId || machine?.app_id === appId)
			.map((machine) => summarizeMachine(machine))
		return {
			count: machines.length,
			organization: orgResult.organization,
			machines,
		}
	}

	const orgResult = await machinesListForOrg({ ...params, state })
	const machines = orgResult.machines.map((machine) => summarizeMachine(machine))
	return {
		count: machines.length,
		organization: orgResult.organization,
		orgSlug: resolveOrgSlug(params),
		machines,
	}
}

export async function getMachine(params = {}) {
	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)
	return {
		machine: summarizeMachine(machine, { name: appName }),
		raw: machine,
	}
}