How-to
Swap the network transport
Replace the mock with your RGS client in one file.
slotplate ships with MockNetworkManager (random grids, 300ms latency).
Real games talk to an RGS over WebSocket or HTTPS.
The interface
export interface NetworkManager {
spin(req: SpinRequest): Promise<SpinResponse>;
}
That's it. Write your own class, register it in composition.ts:
container.register<NetworkManager>(
'network',
() => new RgsNetworkManager(config.rgsUrl, config.sessionToken),
);
Nothing else in the codebase knows about the transport. Phases call
network.spin(...); the return type is the same. No other change needed.
What goes in the real implementation
- Session handshake / authentication. Usually a one-time call on app boot; store the token in
infrastructure, not in a MobX store. - Request/response logging for support tickets. Log correlation IDs so you can trace a spin end-to-end.
- Retry on transient errors. Finite retries with backoff. Throw loud after N attempts — do not silently return an empty response.
- Schema validation. Don't trust the payload shape. Parse it (Zod, io-ts, hand-rolled) at the boundary and throw if malformed.
What does NOT go here
- Game rules. The server enforces them; the client doesn't recompute.
- UI state.
NetworkManageris infrastructure — it doesn't touchUIStore. - Paytable caching. If you need the paytable on the client (for tooltips), serve it as a separate endpoint.
Testing
Phase tests use a mock NetworkManager via vi.fn() — see
tests/flow/SpinPhase.test.ts. For integration with the real server,
use a dev seed if your RGS supports it. Otherwise, mock at the NetworkManager
boundary only — don't mock deeper.