Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Client Handles

Attachments are per-client state. Client handles are the per-socket API actors use to communicate with connected clients.

Client handle operations

Client handles support the core per-socket operations:

  • yield* client.attachments: read per-socket state
  • yield* client.send(...): emit an event to one client
  • yield* client.save(...): persist updated attachment state for that client
  • yield* client.disconnect: close that client's socket

Actor-wide senders

Actors add whole-actor senders via two groups:

  • TicTacToeActor.all: every connected client
  • TicTacToeActor.others: every client other than currentClient

Each exposes the same send and disconnect shape:

  • yield* TicTacToeActor.all.send(...): broadcast to every connected client
  • yield* TicTacToeActor.all.disconnect: disconnect every connected client
  • yield* TicTacToeActor.others.send(...): broadcast to everyone except the calling client
  • yield* TicTacToeActor.others.disconnect: disconnect everyone except the calling client

Broadcast

Effect.gen(function* () {
  yield* TicTacToeActor.all.send("GameEnded", { winner: player })
})

Selective disconnect

Effect.gen(function* () {
  const { clients } = yield* TicTacToeActor
 
  for (const client of clients) {
    const { player } = yield* client.attachments
    if (bannedPlayers.has(player)) {
      yield* client.disconnect
    }
  }
})

Whole-actor disconnect

Effect.gen(function* () {
  yield* TicTacToeActor.all.disconnect
})

Attachments are not actor storage

client.save(...) updates serialized attachment state for one connected client.

That is useful for values like:

  • the caller's user id
  • the caller's role in a game
  • per-socket cursors or last-seen sequence numbers

Do not use attachments as whole-actor storage. Persist shared state elsewhere, for example through Effect's KeyValueStore interface backed by an R2 bucket.