1import * as Hetzner from "alchemy/Hetzner";
2import * as Effect from "effect/Effect";
3import * as FileSystem from "effect/FileSystem";
4import { HttpServerRequest } from "effect/http/HttpServerRequest";
5import * as HttpServerResponse from "effect/http/HttpServerResponse";
6import { API_PORT, Box, Data, MARKER_FILE, VOLUME_PATH } from "./shared.ts";
7
8/**
9 * HTTP Service: mounts the shared Volume and serves the marker file
10 * {@link Worker} writes.
11 */
12export default class Api extends Hetzner.Service<Api>()(
13 "Api",
14 {
15 server: Box,
16 main: import.meta.url,
17 port: API_PORT,
18 },
19 Effect.gen(function* () {
20 const volume = yield* Data;
21 const mount = yield* Hetzner.MountVolume(volume, { path: VOLUME_PATH });
22
23 return {
24 fetch: Effect.gen(function* () {
25 const request = yield* HttpServerRequest;
26 const url = new URL(request.url, "http://service");
27 if (url.pathname === "/health") {
28 return yield* HttpServerResponse.json({
29 ok: true,
30 path: mount.path,
31 });
32 }
33 const fs = yield* FileSystem.FileSystem;
34 const text = yield* fs.readFileString(MARKER_FILE).pipe(Effect.orDie);
35 return yield* HttpServerResponse.json({
36 path: mount.path,
37 device: mount.device,
38 text,
39 });
40 }),
41 };
42 }).pipe(Effect.provide(Hetzner.MountVolumeLive)),
43) {}