| 1 | import type { ReadBucketClient } from "@/Cloudflare/R2/ReadBucket.ts"; |
| 2 | import * as Effect from "effect/Effect"; |
| 3 | import * 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 | */ |
| 11 | export 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 | }); |