import { mkdir, readFile, rm, writeFile } from "node:fs/promises"; import { join } from "node:path"; import { defineCommand } from "citty"; import { apiRequest, type ApiRequestInit } from "../lib/api"; import type { MaintenanceStatus } from "../shared/api"; type Request = (path: string, init?: ApiRequestInit) => Promise; type Confirmation = (host: string) => Promise; const confirmationPath = join( process.env.XDG_RUNTIME_DIR ?? "/tmp", "kuber", "maintenance-confirmation", ); const TTL_MS = 60_000; async function confirmed(host: string): Promise { try { const value = JSON.parse(await readFile(confirmationPath, "utf8")) as { host?: string; expiresAt?: number; }; if ( value.host === host && typeof value.expiresAt === "number" && value.expiresAt > Date.now() ) { await rm(confirmationPath, { force: true }); return true; } } catch {} await mkdir(join(confirmationPath, ".."), { recursive: true, mode: 0o700 }); await writeFile( confirmationPath, JSON.stringify({ host, expiresAt: Date.now() + TTL_MS }), { mode: 0o600 }, ); return false; } export async function runMaintenance( host: string, request: Request = apiRequest, confirm: Confirmation = confirmed, ): Promise { const status = await request( `/maintenance/${encodeURIComponent(host)}`, ); if (!(await confirm(status.host))) { console.log( `${status.host} maintenance is currently ${status.enabled ? "\x1b[31mON\x1b[0m" : "\x1b[32mOFF\x1b[0m"}, run this command again to toggle.`, ); return status; } const result = await request( `/maintenance/${encodeURIComponent(status.host)}`, { method: "POST", json: { enabled: !status.enabled } }, ); console.log( `${result.host} maintenance is now ${result.enabled ? "\x1b[31mON\x1b[0m" : "\x1b[32mOFF\x1b[0m"}`, ); return result; } export const maintenance = defineCommand({ meta: { name: "maintenance", description: "Toggle a global hostname maintenance override", }, args: { host: { type: "positional", required: true, description: "DNS hostname" }, }, async run({ args }) { await runMaintenance(args.host); }, });