1import type { ReadBucketClient } from "@/Cloudflare/R2/ReadBucket.ts";
2import * as Effect from "effect/Effect";
3import * as HttpServerResponse from "effect/http/HttpServerResponse";
4
5/**
6 * Shared read-side routes exercised by both the binding and HTTP fixtures so
7 * every method of {@link ReadBucketClient} (`get`, `head`, `list`) is driven
8 * over `fetch`. Returns `undefined` when the path is not a read route so the
9 * caller can fall through (used by the read-write fixtures).
10 */
11export const readRoutes = (r2: ReadBucketClient, url: URL) =>
12 Effect.gen(function* () {
13 if (url.pathname === "/get") {
14 const key = url.searchParams.get("key") ?? "";
15 const object = yield* r2.get(key).pipe(Effect.orDie);
16 const value = object ? yield* object.text().pipe(Effect.orDie) : null;
17 return yield* HttpServerResponse.json({ value });
18 }
19 if (url.pathname === "/head") {
20 const key = url.searchParams.get("key") ?? "";
21 const object = yield* r2.head(key).pipe(Effect.orDie);
22 return yield* HttpServerResponse.json({
23 exists: object !== null,
24 size: object?.size ?? null,
25 });
26 }
27 if (url.pathname === "/list") {
28 const prefix = url.searchParams.get("prefix") ?? undefined;
29 const result = yield* r2
30 .list(prefix ? { prefix } : undefined)
31 .pipe(Effect.orDie);
32 return yield* HttpServerResponse.json({
33 keys: result.objects.map((o) => o.key),
34 });
35 }
36 return undefined;
37 });