RPCs
Some actions aren’t “write a value” — they’re “ask the server to do a thing”: play a card, fire a weapon, buy an item. Those are RPCs: typed functions the client calls and the server handles, with the argument and return types shared from one definition.
Define
// irtio/rpc.ts
import { defineRpc, number, string } from '@irtio/rpc';
export const rpc = defineRpc({
playCard: { args: { card: string() }, returns: { ok: boolean() } },
fire: { args: { angle: number(), power: number() } },
}); Handle on the server
The handler receives the current state, the typed args, and a context with the caller’s identity. It runs authoritatively — the client can’t skip it.
// irtio/room.ts
export default defineRoom(schema, {
rpc: {
playCard(state, { card }, ctx) {
const hand = state.hands[ctx.clientId];
if (!hand.includes(card)) return { ok: false }; // reject cheating
hand.splice(hand.indexOf(card), 1);
state.pile.push(card);
return { ok: true };
},
},
}); Call from the client
const { ok } = await room.rpc.playCard({ card: '10♣' });
if (!ok) shake(); The resulting state changes stream back through your normal subscribe — you
don’t apply the RPC’s effects yourself.
When to use an RPC vs. an owned write
| Reach for… | When |
|---|---|
| Owned write | you own the value and just want it synced |
| RPC | the server must validate, arbitrate, or compute the result |
Next steps
Placeholder content.