Skip to content

Contract entry shapes

Every entry in a contract picks an interaction flavor by its shape. This is the field-by-field reference; for the model and when to use each, see The contract.

The five flavors

FlavorWhere it livesShapeInitiated by
requestclientToServer{ input, output }client calls, awaits one reply
eventserverToClient{ payload }server pushes to recipients it picks
topicserverToClient{ payload, subscribe: true }client subscribes; server publishes
roomserver API (srv.room(id))— (broadcasts a shared event)server owns membership
server-requestserverToClient{ input, output }server calls the client, awaits a reply

A serverToClient entry is an event by default; subscribe: true promotes it to a topic. A serverToClient entry with both input and output is a server-request (the server calls srv.toConn(id).request(...); the client answers via client.implement).

Field reference

ts
// request — clientToServer
name: { input: Schema, output: Schema }

// event — serverToClient
name: { payload: Schema }

// topic — serverToClient (client opt-in)
name: { payload: Schema, subscribe: true }

// server-request — serverToClient (server calls, client replies)
name: { input: Schema, output: Schema }
FieldTypeApplies toNotes
inputStandard Schemarequest, server-requestvalidated before the handler runs
outputStandard Schemarequest, server-requesttyped back to the caller
payloadStandard Schemaevent, topicvalidated on the wire
subscribetruetopicabsent ⇒ event

Any Standard Schema validator works (Zod, Valibot, ArkType). The same schema types and validates the value.

The two axes

ts
defineContract({
  shared: {                     // every role inherits these
    clientToServer: { /* requests */ },
    serverToClient: { /* events + topics */ },
  },
  roles: {                      // each role sees shared ∪ its own block
    user:  { clientToServer: {…}, serverToClient: {…} },
    agent: { clientToServer: {…}, serverToClient: {…} },
  },
  collections: { /* rows + CRDT docs */ }, // see /collections/
  plugins: [ /* contract fragments */ ],   // see /concepts/plugins
})

The effective surface for a role is shared ∪ roles[R]. A call outside it is rejected with NOT_FOUND. A shared topic also types the cluster event bus (server.publish / server.subscribe).

See also: Collections (the collections block) · API reference.

Released under the MIT License.