1import type { ReadNamespaceClient } from "@/Cloudflare/KV/ReadNamespace.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 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 */
18export 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 });