1import * as Layer from "effect/Layer";
2import * as FetchHttpClient from "effect/http/FetchHttpClient";
3import * as AtomRpc from "effect/reactivity/AtomRpc";
4import { RpcClient, RpcSerialization } from "effect/rpc";
5import { TodoRpcs } from "./backend/rpc.ts";
6
7/**
8 * The browser-side reactive RPC client. Effect 4 ships atom RPC natively in
9 * `effect/reactivity/AtomRpc` — `AtomRpc.Service` turns an `RpcGroup`
10 * into a `.query()` / `.mutation()` client whose results are atoms.
11 *
12 * The transport (`protocol`) is a plain HTTP client over `fetch`, pointed at
13 * the same-origin `/rpc` route which proxies to the backend service binding.
14 * Serialization MUST match the backend (`RpcSerialization.layerJson`).
15 */
16export class TodoClient extends AtomRpc.Service<TodoClient>()("TodoClient", {
17 group: TodoRpcs,
18 protocol: RpcClient.layerProtocolHttp({ url: "/rpc" }).pipe(
19 Layer.provide(FetchHttpClient.layer),
20 Layer.provide(RpcSerialization.layerJson),
21 ),
22}) {}
23
24/**
25 * Query/mutation atoms, created once at module scope so their identity is stable
26 * across renders. `reactivityKeys: ["todos"]` ties the list query to the
27 * mutations below — when a mutation runs with the same key, the list refetches.
28 */
29export const listTodosAtom = TodoClient.query("listTodos", undefined, {
30 reactivityKeys: ["todos"],
31});
32export const createTodoAtom = TodoClient.mutation("createTodo");
33export const toggleTodoAtom = TodoClient.mutation("toggleTodo");
34export const deleteTodoAtom = TodoClient.mutation("deleteTodo");