| 1 | import type { ReadNamespaceClient } from "@/Cloudflare/KV/ReadNamespace.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 ReadNamespaceClient} is driven over `fetch`: |
| 8 | * |
| 9 | * - `GET /get?key=` — `get(key)` (text, the default). |
| 10 | * - `GET /get-json?key=` — `get(key, "json")` (parsed JSON value). |
| 11 | * - `GET /get-bulk?keys=a,b` — `get([...], "text")` (bulk read → `Map`). |
| 12 | * - `GET /getWithMetadata?key=` — `getWithMetadata(key)` (value + metadata). |
| 13 | * - `GET /list?prefix=` — `list()` / `list({ prefix })`. |
| 14 | * |
| 15 | * Returns `undefined` when the path is not a read route so the caller can fall |
| 16 | * through (used by the read-write fixtures). |
| 17 | */ |
| 18 | export const readRoutes = (kv: ReadNamespaceClient, url: URL) => |
| 19 | Effect.gen(function* () { |
| 20 | if (url.pathname === "/get") { |
| 21 | const key = url.searchParams.get("key") ?? ""; |
| 22 | const value = yield* kv.get(key).pipe(Effect.orDie); |
| 23 | return yield* HttpServerResponse.json({ value }); |
| 24 | } |
| 25 | if (url.pathname === "/get-json") { |
| 26 | const key = url.searchParams.get("key") ?? ""; |
| 27 | const value = yield* kv.get(key, "json").pipe(Effect.orDie); |
| 28 | return yield* HttpServerResponse.json({ value }); |
| 29 | } |
| 30 | if (url.pathname === "/get-bulk") { |
| 31 | const keys = (url.searchParams.get("keys") ?? "") |
| 32 | .split(",") |
| 33 | .filter((k) => k.length > 0); |
| 34 | const values = yield* kv.get(keys, "text").pipe(Effect.orDie); |
| 35 | return yield* HttpServerResponse.json({ |
| 36 | values: Object.fromEntries(values), |
| 37 | }); |
| 38 | } |
| 39 | if (url.pathname === "/getWithMetadata") { |
| 40 | const key = url.searchParams.get("key") ?? ""; |
| 41 | const result = yield* kv.getWithMetadata(key).pipe(Effect.orDie); |
| 42 | return yield* HttpServerResponse.json({ |
| 43 | value: result.value, |
| 44 | metadata: result.metadata, |
| 45 | }); |
| 46 | } |
| 47 | if (url.pathname === "/list") { |
| 48 | const prefix = url.searchParams.get("prefix") ?? undefined; |
| 49 | const result = yield* kv |
| 50 | .list(prefix ? { prefix } : undefined) |
| 51 | .pipe(Effect.orDie); |
| 52 | return yield* HttpServerResponse.json({ |
| 53 | keys: result.keys.map((k) => k.name), |
| 54 | }); |
| 55 | } |
| 56 | return undefined; |
| 57 | }); |