One zero-dependency package for browsers, Node.js and TypeScript — full REST coverage plus a WebSocket realtime client with an optional UDP fast lane on Node.
Plain ESM on native fetch and WebSocket. No build step, no polyfills, ~19 kB packed — auditable in one sitting.
WebSocket control channel everywhere; the MUR1 UDP fast lane activates on Node.js via node:dgram — the same wire protocol the native SDKs speak.
Ships index.d.ts covering every method and response — TypeScript autocomplete and compile checks with no codegen and no any-typed public surface.
# Download SDK.zip from this page, extract it, then point npm at the folder:
npm install ./michitai-multiplayer # file: dependency on the extracted package
# Or skip npm entirely — copy src/ + index.d.ts into your project
# (zero dependencies; a vendored copy is identical).
The package is not yet published to the npm registry — npm install michitai-multiplayer will only work after the first published release. Today the canonical artifact is the zip below: it contains the complete package (package.json included), so installing it as a file: dependency gives you the same result, with versions and lockfile entries working normally.
| Environment | Support |
|---|---|
| Node.js ≥ 22.12 (recommended: 24 LTS) | Full — REST, WS realtime, UDP lane, CLI, ESM + CJS |
| Browsers (Chrome/Edge/Firefox/Safari) | REST + WS realtime; UDP unavailable by platform |
| TypeScript | Via bundled declarations — --strict-clean, verified under nodenext |
| Deno / Bun / edge runtimes | Not verified — untested, not claimed |
Node 22.12 is the floor because the SDK uses the unflagged global WebSocket and require()-of-ESM for the CommonJS entry — see Node.js usage for the version policy.
import { MultiplayerClient } from 'michitai-multiplayer';
const mp = new MultiplayerClient('YOUR_API_TOKEN');
// register a player — private_key is the per-player credential, store it
const reg = await mp.players.register('PlayerOne', { playerData: { wins: 0 } });
const playerToken = reg.private_key;
// create a realtime-enabled room
const room = await mp.rooms.create(playerToken, 'Lobby 1',
{ maxPlayers: 4, realtime: true });
// open the realtime channel
const tok = await mp.realtime.get(playerToken);
const rt = mp.createRealtime({
onReceive: (command, data, sender) => handleMessage(command, data, sender),
});
await rt.connect(tok.token, tok.realtime_server);
rt.send('all', 'chat', { text: 'hello lobby' });
Every call returns the parsed response object — check res.success and res.error. API failures don't throw; transport failures throw TransportError, misuse throws ConfigurationError.
The API answers CORS preflights on every endpoint, so the SDK runs directly in a web page — this is a supported configuration, not a hack. One rule matters: only the public API token and player tokens may appear in client code. The private token (X-Api-Private-Token) unlocks admin endpoints and must live exclusively on infrastructure you control. If you need admin operations triggered by a web UI, proxy them through your own backend.
Persist the player token in localStorage so returning visitors keep their account; rotate it with mp.players.rotate() if a device may be compromised. Full browser notes: WebGL & browser games.
mp.players — register, login, heartbeat, rename, rotate, ban/unban, datamp.rooms — create/list/join/leave/current/stop/kick/passwordmp.actions — request/response room actionsmp.updates — persistent room statemp.matchmaking + matchmakingRequestsmp.leaderboard — ranked queries over player datamp.friends — lists, requests, invites, Steam importmp.moderation, mp.time, mp.realtime, mp.gamesconnect(token, server) — WS handshake, resolves on the connected envelopesend(target, command, data) — reliable; targets: all|host|others|specificsendUnreliable(...) — UDP when bound, WS fallback otherwiseconnectUdp() — Node-only MUR1 datagram laneonConnected/onReceive/onSent/onError/onClose.npmrc and registry configurationFree tier — full API surface, no credit card. The SDK license permits bundling into commercial games.