A simple, zero-configuration script to quickly boot FreeBSD ISO images using QEMU

refactor: reorganize error handling and request parsing in API utilities

Changed files
+78 -74
src
+10 -73
src/api/machines.ts
··· 1 - import { type Context, Hono } from "hono"; 2 - import { Data, Effect, pipe } from "effect"; 3 - import { parseParams, parseQueryParams, presentation } from "./utils.ts"; 1 + import { Hono } from "hono"; 2 + import { Effect, pipe } from "effect"; 3 + import { 4 + handleError, 5 + parseParams, 6 + parseQueryParams, 7 + parseStartRequest, 8 + presentation, 9 + } from "./utils.ts"; 4 10 import { getInstanceState } from "../mod.ts"; 5 11 import { listInstances } from "../state.ts"; 6 - import { 7 - type CommandError, 8 - findVm, 9 - killProcess, 10 - StopCommandError, 11 - updateToStopped, 12 - VmNotFoundError, 13 - } from "../subcommands/stop.ts"; 12 + import { findVm, killProcess, updateToStopped } from "../subcommands/stop.ts"; 14 13 import { 15 14 buildQemuArgs, 16 15 createLogsDir, 17 16 setupFirmware, 18 17 startDetachedQemu, 19 18 } from "../subcommands/start.ts"; 20 - import { MachineParamsSchema } from "../types.ts"; 21 - 22 - class ParseRequestError extends Data.TaggedError("ParseRequestError")<{ 23 - cause?: unknown; 24 - message: string; 25 - }> {} 26 - 27 - export const handleError = ( 28 - error: 29 - | VmNotFoundError 30 - | StopCommandError 31 - | CommandError 32 - | ParseRequestError 33 - | Error, 34 - c: Context, 35 - ) => 36 - Effect.sync(() => { 37 - if (error instanceof VmNotFoundError) { 38 - return c.json( 39 - { message: "VM not found", code: "VM_NOT_FOUND" }, 40 - 404, 41 - ); 42 - } 43 - if (error instanceof StopCommandError) { 44 - return c.json( 45 - { 46 - message: error.message || 47 - `Failed to stop VM ${error.vmName}`, 48 - code: "STOP_COMMAND_ERROR", 49 - }, 50 - 500, 51 - ); 52 - } 53 - 54 - if (error instanceof ParseRequestError) { 55 - return c.json( 56 - { 57 - message: error.message || "Failed to parse request body", 58 - code: "PARSE_BODY_ERROR", 59 - }, 60 - 400, 61 - ); 62 - } 63 - 64 - return c.json( 65 - { message: error instanceof Error ? error.message : String(error) }, 66 - 500, 67 - ); 68 - }); 69 - 70 - const parseStartRequest = (c: Context) => 71 - Effect.tryPromise({ 72 - try: async () => { 73 - const body = await c.req.json(); 74 - return MachineParamsSchema.parse(body); 75 - }, 76 - catch: (error) => 77 - new ParseRequestError({ 78 - cause: error, 79 - message: error instanceof Error ? error.message : String(error), 80 - }), 81 - }); 82 19 83 20 const app = new Hono(); 84 21
+68 -1
src/api/utils.ts
··· 1 - import { Effect } from "effect"; 1 + import { Data, Effect } from "effect"; 2 2 import type { Context } from "hono"; 3 + import { 4 + type CommandError, 5 + StopCommandError, 6 + VmNotFoundError, 7 + } from "../subcommands/stop.ts"; 8 + import { MachineParamsSchema } from "../types.ts"; 3 9 4 10 export const parseQueryParams = (c: Context) => Effect.succeed(c.req.query()); 5 11 ··· 7 13 8 14 export const presentation = (c: Context) => 9 15 Effect.flatMap((data) => Effect.succeed(c.json(data))); 16 + 17 + export class ParseRequestError extends Data.TaggedError("ParseRequestError")<{ 18 + cause?: unknown; 19 + message: string; 20 + }> {} 21 + 22 + export const handleError = ( 23 + error: 24 + | VmNotFoundError 25 + | StopCommandError 26 + | CommandError 27 + | ParseRequestError 28 + | Error, 29 + c: Context, 30 + ) => 31 + Effect.sync(() => { 32 + if (error instanceof VmNotFoundError) { 33 + return c.json( 34 + { message: "VM not found", code: "VM_NOT_FOUND" }, 35 + 404, 36 + ); 37 + } 38 + if (error instanceof StopCommandError) { 39 + return c.json( 40 + { 41 + message: error.message || 42 + `Failed to stop VM ${error.vmName}`, 43 + code: "STOP_COMMAND_ERROR", 44 + }, 45 + 500, 46 + ); 47 + } 48 + 49 + if (error instanceof ParseRequestError) { 50 + return c.json( 51 + { 52 + message: error.message || "Failed to parse request body", 53 + code: "PARSE_BODY_ERROR", 54 + }, 55 + 400, 56 + ); 57 + } 58 + 59 + return c.json( 60 + { message: error instanceof Error ? error.message : String(error) }, 61 + 500, 62 + ); 63 + }); 64 + 65 + export const parseStartRequest = (c: Context) => 66 + Effect.tryPromise({ 67 + try: async () => { 68 + const body = await c.req.json(); 69 + return MachineParamsSchema.parse(body); 70 + }, 71 + catch: (error) => 72 + new ParseRequestError({ 73 + cause: error, 74 + message: error instanceof Error ? error.message : String(error), 75 + }), 76 + });