| 1 | import * as Layer from "effect/Layer"; |
| 2 | import * as FetchHttpClient from "effect/http/FetchHttpClient"; |
| 3 | import * as AtomRpc from "effect/reactivity/AtomRpc"; |
| 4 | import { RpcClient, RpcSerialization } from "effect/rpc"; |
| 5 | import { 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 | */ |
| 16 | export 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 | */ |
| 29 | export const listTodosAtom = TodoClient.query("listTodos", undefined, { |
| 30 | reactivityKeys: ["todos"], |
| 31 | }); |
| 32 | export const createTodoAtom = TodoClient.mutation("createTodo"); |
| 33 | export const toggleTodoAtom = TodoClient.mutation("toggleTodo"); |
| 34 | export const deleteTodoAtom = TodoClient.mutation("deleteTodo"); |