Skip to content

Getting Started ​

This guide gets one app connected to a running swu-simulator server. The SDK does not start the engine; it speaks to the HTTP and WebSocket API exposed by the server.

First-party consumer ​

The SDK's primary consumer today is the swu Nuxt 4 app that lives beside this repository at ../swu. It exercises the whole surface rather than a subset: createSimulatorClient for browser and server-side calls, MatchSession for live matches, and the offline path through @my-swu/simulator-client/local, /local/assets, /local/routing, and the shipped wasm engine.

That app does not install a published version. It depends on this workspace directly:

json
{
  "dependencies": {
    "@my-swu/simulator-client": "link:../swu-simulator/packages/ts-sdk"
  }
}

A linked consumer still resolves through the package exports map, which points at dist/. Editing SDK source therefore changes nothing in ../swu until the SDK is rebuilt. When you change the SDK for that app, the loop includes a build:

bash
# From the swu-simulator repo root. Re-exports the schema and rebuilds the SDK.
pnpm sdk:build
bash
# TypeScript only, when the Rust schema has not changed.
pnpm --filter @my-swu/simulator-client run build

Everything below applies equally to a normal npm install.

Install ​

bash
pnpm add @my-swu/simulator-client
bash
npm install @my-swu/simulator-client
bash
yarn add @my-swu/simulator-client

Start the simulator ​

From the simulator repository:

bash
cargo run --bin swu-simulator

The examples assume the server is reachable at http://127.0.0.1:4000. They also use card ids from the simulator card cache; see card ids for the mapping used in snippets.

Create a client ​

ts
import { 
createSimulatorClient
} from '@my-swu/simulator-client'
export const
simulatorClient
=
createSimulatorClient
({
// This is the HTTP origin of the running simulator server.
baseUrl
: 'http://127.0.0.1:4000',
})

Check connectivity:

ts
const 
health
= await
simulatorClient
.
system
.
health
()
console
.
log
(
health
.
status
) // "ok"

Runtime requirements ​

  • Node.js 18+ or any runtime with global fetch.
  • A browser-style WebSocket global for live match sockets.
  • ESM only. Use "type": "module" or dynamic import() in CommonJS projects.

Node does not provide a browser WebSocket global. Inject one when you need live match sockets:

ts
import 
WebSocket
from 'ws'
import {
createSimulatorClient
} from '@my-swu/simulator-client'
import type {
WebSocketFactory
} from '@my-swu/simulator-client'
// Node examples use `ws` to provide the browser-compatible socket shape. const
nodeWebSocketFactory
:
WebSocketFactory
=
url
=> new
WebSocket
(
url
)
const
simulatorClient
=
createSimulatorClient
({
baseUrl
: 'http://127.0.0.1:4000',
// Required only for live match sockets in runtimes without global WebSocket.
webSocketFactory
:
nodeWebSocketFactory
,
})

First match ​

ts
// Use card ids; these example card ids map to real cards.
const 
premierHostDeck
= {
leader
: 46102, // Leia Organa - Someone Who Loves You
// Twin Suns decks list every leader here; single-leader formats send an empty array.
leaders
: [],
base
: 308, // Echo Base
cards
:
Array
.
from
({
length
: 50 }, () => 45), // Alliance X-Wing
// Only formats whose validation allows a sideboard accept entries here.
sideboard
: [],
} const
hostAccess
= await
simulatorClient
.
matches
.
create
({
// Seeds make examples deterministic.
seed
: '7',
format
: 'premier',
// Twin Suns supports 2-4 players; every other format is exactly 2.
playerCount
: 2,
hostDeck
:
premierHostDeck
,
// Every viewer sees this name on the host seat.
hostName
: 'Host',
// True only when the host arrived from an authenticated app session.
hostAuthenticated
: false,
// Identities that should own this match in server-side history.
historyIdentities
: [],
// One entry per AI-controlled seat; empty means a human opponent joins.
aiOpponents
: [],
}) // The session stores the returned private access and owns socket state. const
matchSession
=
simulatorClient
.
session
.
create
(
hostAccess
)
await
matchSession
.
connect
()
matchSession
.
on
('snapshot',
matchSnapshot
=> {
// Render from snapshots; they are the authoritative game state.
console
.
log
(
matchSnapshot
.
prompt
)
}) // Signal that this seat is ready to leave the lobby.
matchSession
.
ready
()

Read next:

Released under the MIT License.