Skip to main content

Typed Communication

By default, extra data exchanged between the Game Client and the RGS is untyped (unknown). You can provide custom codecs to get fully typed sdk.openGame() and sdk.play() calls — both the extra request payload and the response data will be inferred from your codec definitions.

How it works

Codecs handle encoding (Game Client → RGS) and decoding (RGS → Game Client). The RGS typically communicates extra data as a JSON string, while the game works with typed TypeScript objects. Codecs bridge this gap transparently.

A codec implements encode and decode:

interface Codec<TEncoded, TDecoded> {
encode: (value: TDecoded) => TEncoded
decode: (value: TEncoded) => TDecoded
}

Example

import { KalambaSdk, type Codecs } from '@kalamba/sdk'

// Game state returned by RGS in openGame and play responses
interface GameState {
level: number
multiplier: number
symbols: string[]
}

// Player choice sent as extra data in play requests
interface PlayerChoice {
pickedOption: 'left' | 'center' | 'right'
}

// RGS returns extra data as a JSON string
const responseCodec = {
encode: (value: GameState): string => JSON.stringify(value),
decode: (value: string): GameState => JSON.parse(value),
}

// RGS requires extra data as a JSON string
const playRequestCodec = {
encode: (value: PlayerChoice): string => JSON.stringify(value),
decode: (value: string): PlayerChoice => JSON.parse(value),
}

const emptyCodec = {
encode: () => ({}),
decode: () => ({}),
}

const codecs = {
openGame: { request: emptyCodec, response: responseCodec },
play: { request: playRequestCodec, response: responseCodec },
} satisfies Codecs

const sdk = new KalambaSdk({ messagePort: window.parent, codecs })

// openGame() — no extra data, response.data is typed as GameState
const { data } = await sdk.openGame()

// play() — extra accepts PlayerChoice, response.data is typed as GameState
const { data } = await sdk.play(contractPayload, { pickedOption: 'left' })

With this setup:

  • sdk.openGame() does not accept extra data and returns { data: GameState }
  • sdk.play(contract, extra) requires extra to be PlayerChoice and returns { data: GameState }
  • Passing incorrect types to extra or accessing wrong properties on data will produce TypeScript errors at compile time
tip

The codec interface is compatible with Zod codecs, so you can use z.codec() if you prefer schema-based validation and transformation.