1import * as Schema from "effect/Schema";
2import * as Rpc from "effect/rpc/Rpc";
3import * as RpcGroup from "effect/rpc/RpcGroup";
4
5/**
6 * Shared domain + RPC contract.
7 *
8 * This module is the single source of truth imported by BOTH ends:
9 * - the backend `Cloudflare.Workers.RpcWorker` ({@link ./api.ts}) serves it, and
10 * - the browser `AtomRpc` client ({@link ./rpc-client.ts}) consumes it.
11 *
12 * One `Schema` codec round-trips every value over the wire, so the React UI is
13 * fully typed against the same shapes the Postgres-backed handlers return.
14 */
15
16/** A single todo item, encoded over the wire and decoded back into this class. */
17export class Todo extends Schema.Class<Todo>("Todo")({
18 id: Schema.Number,
19 text: Schema.String,
20 done: Schema.Boolean,
21 createdAt: Schema.Date,
22}) {}
23
24/** Raised when a mutation targets a todo id that no longer exists. */
25export class TodoNotFound extends Schema.TaggedErrorClass<TodoNotFound>()(
26 "TodoNotFound",
27 { message: Schema.String, id: Schema.Number },
28) {}
29
30export class TodoRpcs extends RpcGroup.make(
31 Rpc.make("listTodos", {
32 success: Schema.Array(Todo),
33 }),
34 Rpc.make("createTodo", {
35 payload: { text: Schema.String },
36 success: Todo,
37 }),
38 Rpc.make("toggleTodo", {
39 payload: { id: Schema.Number, done: Schema.Boolean },
40 success: Todo,
41 error: TodoNotFound,
42 }),
43 Rpc.make("deleteTodo", {
44 payload: { id: Schema.Number },
45 success: Schema.Number,
46 error: TodoNotFound,
47 }),
48) {}