1import * as Railway from "@/Railway";
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 { Partition, Site } from "./suite-env.ts";
7
8export { Site };
9
10export const VOLUME_PATH = "/data";
11export const MARKER_FILE = "hello.txt";
12export const MARKER = "hello-from-railway-volume";
13export const VOLUME_PORT = 3000;
14
15/**
16 * Block disk {@link VolumeApi} mounts at {@link VOLUME_PATH}.
17 */
18export const Data = Railway.Volume("Data", {
19 project: Site,
20 environment: Partition,
21 mountPath: VOLUME_PATH,
22});
23
24/**
25 * HTTP Service that mounts {@link Data} via {@link Railway.MountVolume}
26 * and round-trips a file — the Volume tutorial shape.
27 */
28export default class VolumeApi extends Railway.Service<VolumeApi>()(
29 "VolumeApi",
30 {
31 project: Site,
32 environment: Partition,
33 main: import.meta.url,
34 port: VOLUME_PORT,
35 },
36 Effect.gen(function* () {
37 const mount = yield* Railway.MountVolume(Data, { path: VOLUME_PATH });
38 const fs = yield* FileSystem.FileSystem;
39
40 return {
41 fetch: Effect.gen(function* () {
42 const request = yield* HttpServerRequest;
43 const url = new URL(request.url, "http://service");
44 if (url.pathname === "/health") {
45 return yield* HttpServerResponse.json({
46 ok: true,
47 path: mount.path,
48 });
49 }
50 const file = `${mount.path}${url.pathname}`;
51 if (request.method === "PUT") {
52 const body = yield* request.text;
53 yield* fs.writeFileString(file, body).pipe(Effect.orDie);
54 return HttpServerResponse.empty({ status: 204 });
55 }
56 if (request.method === "GET") {
57 const text = yield* fs
58 .readFileString(file)
59 .pipe(Effect.catch(() => Effect.succeed(undefined)));
60 if (text === undefined) {
61 return HttpServerResponse.text("Not found", { status: 404 });
62 }
63 return HttpServerResponse.text(text);
64 }
65 return HttpServerResponse.text("Hello from Railway!");
66 }),
67 };
68 }).pipe(Effect.provide(Railway.MountVolumeLive)),
69) {}