Quick start
From install to synchronized state.
Create the client, subscribe before startup, and render the complete lifecycle from one immediate store.
npm install @w3booster/sdkimport { createClient } from '@w3booster/sdk';
const lifetime = new AbortController();
const client = createClient({
clientId: 'your_app_id',
signal: lifetime.signal
});
client.lifecycle.subscribe(snapshot => {
renderConnection(snapshot.status);
if (snapshot.state) renderMatch(snapshot.state);
}, { signal: lifetime.signal });
await client.start();
// Component or page teardown:
lifetime.abort();start() resolves after the current connection has a synchronized state. Application code does not choose a WebSocket, carry credentials, apply patches, or implement reconnection.
Develop without W3Booster
Demo mode loads a representative fixture on demand and keeps demo code out of normal production startup.
const client = createClient({
clientId: 'your_app_id',
demo: true
});
await client.start();Pass demo: { interval: 0, settings: { … } } for a deterministic fixture, or provide a complete demo state for focused UI tests.
Application model
One app. Up to three surfaces.
Every W3Booster app is a remotely hosted web application. Configure only the surfaces the product needs; hosting it yourself or through W3Booster does not change the SDK.
An interactive dashboard or workspace opened inside the client.
A transparent surface composed into the user’s stable OBS browser source.
A transparent surface aligned over Warcraft III by the desktop host.
- Enable Developer ModeUse the account menu in W3Booster, then open Apps → Developer.
- Create a private appAdd its name, public client ID binding, requested scopes, and at least one HTTPS surface.
- Build and testUse demo data for UI work and an owner-only local session for real match data.
- Invite testersPrivate invitation codes grant discovery; each tester still installs and enables the app.
Local development
Use real data without deploying.
Run Vite, Angular, or any web server on localhost. In your app’s developer page, choose Test locally and add the local URLs for the surfaces you are working on.
http://localhost:5173/Owner only · expires after 12 hoursThe session installs and enables the app only for its owner and temporarily replaces only the chosen surfaces. Published metadata and other users do not change. Return to the published version at any time.
// Normal application code stays environment-free.
const client = createClient({ clientId: 'your_app_id' });
// Only platform developers normally force a backend.
const local = createClient({
clientId: 'your_app_id',
backend: 'local'
});Cloud is the default. W3Booster may add ?backend=local or ?backend=cloud to a platform launch, and the SDK honors it automatically. Use backend: 'auto' only when intentionally trying local before cloud.
Frontend lifecycle
Render connection, freshness, and state together.
client.lifecycle is the preferred UI boundary. Its snapshot contains status, state, isSynchronized, and the current connection error. It publishes immediately and after every transition.
const client = createClient({
clientId: 'your_app_id',
retry: true,
signal
});
client.lifecycle.subscribe(({ status, state, isSynchronized, error }) => {
render({ status, state, fresh: isSynchronized, error });
}, { signal });
await client.start({ signal });| Method | Resolves when | Use it for |
|---|---|---|
start() | A fresh synchronized state exists by default | Canonical long-lived frontend startup |
connect() | The transport is connected | Low-level transport control |
whenReady() | Any hydrated state exists, including preserved reconnect state | Work that can use temporarily stale state |
whenSynchronized() | A fresh snapshot for the current connection exists | Rendering or actions that require a current baseline |
Automatic reconnect preserves hydrated state for visual continuity but sets isSynchronized to false until a fresh snapshot arrives. State is recursively immutable and structurally shared, so unchanged branches preserve identity.
State and scopes
One hydrated, capability-aware match model.
The platform filters data before serialization. A scope expresses which branch an app may read; it is not a subscription tier. state.capabilities is the final runtime answer after the app’s granted scopes, account plan, and match context have been applied. Individual optional values can still be absent when the live source does not provide them.
Available to Basic and PRO accounts when scoped and present.
PRO / ObserverPRO during normal play; also available in observer match state.
| Scope | State branch | Availability | Includes |
|---|---|---|---|
match:read | match | All plans | Lifecycle, time, map, mode, realm, observer/replay flags |
players:read | players[] | All plans | Identity, race, team, color, position |
stats:read | players[].stats | All plans | Rank, league, wins, losses, main account |
heroes:read | players[].heroes[] | PRO / Observer | Level, XP, health, mana, abilities, inventory |
upgrades:read | players[].upgrades | PRO / Observer | Completed, active, and researching upgrades |
resources:read | players[].resources | All plans | Gold, lumber, supply, worker supply |
controlgroups:read | players[].controlgroups | All plans | Front units and group sizes |
overlay:read | overlay.runtime | All plans | HUD scale, score, chat state, team-color preference |
client.state.subscribe(state => {
if (!state) return;
const resources = state.capabilities.includes('resources')
? state.players[0]?.resources
: undefined;
renderResources(resources);
});Complete API data model
Everything W3Booster delivers.
This is the full hydrated MatchState<TSettings> exposed by @w3booster/sdk. The SDK validates it at runtime, freezes it recursively, and maintains it from snapshots and patches.
The field has no W3Booster subscription gate. Its scope and live source data may still make it optional.
The API removes the branch and its capability for a Basic account during normal player matches. Observer match state bypasses the plan gate.
Optional because of match type, source availability, privacy, surface, or app configuration—not because it is necessarily PRO.
MatchState<TSettings>
| Field | Type | Availability | Description |
|---|---|---|---|
capabilities | readonly Capability[] | Always | The data branches actually available now: match, players, stats, heroes, upgrades, resources, controlgroups, and overlay. |
match | Match | All plans | Current match metadata. Without match:read, the root remains present as a neutral no-match value. |
players | readonly Player[] | All plans | One entry per player when at least one player-related scope is available; otherwise an empty array. |
overlay? | OverlayState | All plans | Recorder-derived overlay runtime when overlay:read is available. |
application? | ApplicationState<TSettings> | App launch | The current application identity, surface, development state, and resolved user settings. |
match:readMatch
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Stable match identity; empty only while status is none. |
status | 'starting' | 'running' | 'finished' | 'none' | Yes | Current match lifecycle state. |
gameTime | number | Yes | Elapsed in-game time in whole seconds, excluding paused time. |
mode | string | Yes | Normalized game mode such as 1v1, 2v2, or 4ffa. |
map? | string | No | Human-readable, display-ready map name. |
realm? | string | No | Match service or realm, for example W3Champions or Battle.net context. |
paused? | boolean | No | Whether the current game clock is paused. |
isReplay? | boolean | No | Whether W3Booster is reading a replay. |
isReforged? | boolean | No | Selects Reforged versus Classic presentation assets. |
isObserver? | boolean | No | Whether the active match state is an observer context. This is the API-side bypass for PRO-only match branches. |
broadcasterPlayerId? | string | No | Public player ID associated with the broadcaster. |
realBroadcasterPlayerId? | string | No | Underlying broadcaster player ID when presentation identity differs. |
startedAt? | string | No | ISO-8601 match start timestamp. |
players:read + related scopesPlayer
| Field | Type | Scope / plan | Description |
|---|---|---|---|
id | string | Any player branch | Stable identity within the match. |
name? | string | players:read · All plans | Display name, subject to protected-match redaction. |
race? | Race | players:read · All plans | random, human, orc, undead, or night-elf. |
team? | number | players:read · All plans | Zero-based Warcraft team ID. |
colorId? | number | players:read · All plans | Native Warcraft player-color index. |
startPosition? | { x: number; y: number } | players:read · All plans | Warcraft map coordinates, useful for ordering and relative placement—not screen pixels. |
isAI? | boolean | players:read · All plans | Whether this slot is computer-controlled. |
mainAccount? | MainAccount | stats:read · All plans | Resolved main-account identity when one exists. |
stats? | PlayerStatsCollection | stats:read · All plans | Solo, team, 4v4, and FFA ranking collections. |
resources? | Resources | resources:read · All plans | Normalized economy and supply values. |
controlgroups? | Record<string, ControlGroup> | controlgroups:read · All plans | Control-group number to its visible front unit and size. |
heroes? | readonly Hero[] | heroes:read · PRO / Observer | Full hero state. Omitted and removed from capabilities when the plan gate applies. |
upgrades? | UpgradeState | upgrades:read · PRO / Observer | Completed, active, and researching upgrade state. |
Player 2, race random, and no mainAccount. This privacy filtering happens on the trusted server before the app stream is serialized.stats:readPlayerStats
| Field | Type | Description |
|---|---|---|
wins | number | Recorded wins. |
losses | number | Recorded losses. |
winRate | number | Display-ready percentage from 0–100. |
rank? | number | Leaderboard rank. |
league? | string | number | Service-provided league or division. |
level? | number | Service-provided ladder level. |
PlayerStatsCollection may contain solo?, team?, team4?, and ffa?. Use preferredStats() from @w3booster/sdk/standard-game to select the best entry for the match mode.
stats:readMainAccount
| Field | Type | Description |
|---|---|---|
name | string | Resolved main-account name. |
country? | string | Normalized country identifier; resolve its flag with @w3booster/sdk/assets. |
mainRace? | Race | Main-account race when known. |
resources:readResources
| Field | Type | Description |
|---|---|---|
gold | number | Current gold. |
lumber | number | Current lumber. |
supply | number | Used supply. |
supplyCap | number | Current supply cap. |
workerSupply? | number | Supply committed to workers. |
controlgroups:readControlGroup
| Field | Type | Description |
|---|---|---|
frontunit | string | Rawcode of the group’s front unit or building. |
size | number | Number of units/buildings assigned to the group. |
heroes:readHero, HeroAbility, and ValuePool
| Object | Field | Type | Description |
|---|---|---|---|
Hero | id | string | Standard-game hero rawcode used for metadata and artwork lookup. |
name | string | Human-readable hero name. | |
level | number | Current derived hero level. | |
experience? | number | Total hero experience. | |
hitpoints? | ValuePool | Current and maximum hit points. | |
mana? | ValuePool | Current and maximum mana. | |
abilities? | readonly HeroAbility[] | Learned abilities and activation timing. | |
inventory? | readonly string[] | Item rawcodes in slot order. | |
HeroAbility | id | string | Stable identity within the owning hero. |
name | string | Standard-game ability rawcode. | |
level | number | Learned ability level. | |
lastActivation? | number | Milliseconds on the match game-time clock; use the cooldown helper instead of interpreting it directly. | |
ValuePool | current | number | Current value. |
max | number | Maximum value. |
upgrades:readUpgradeState
| Field | Type | Description |
|---|---|---|
upgrades | readonly CompletedUpgrade[] | Completed research and upgrade levels. |
active | readonly ActiveUpgrade[] | Currently relevant active upgrades. |
researching | readonly ResearchingUpgrade[] | Research currently in progress. |
| Upgrade field | Type | Description |
|---|---|---|
name | string | Canonical four-character standard-game upgrade rawcode. |
level | number | Explicit normalized upgrade level. |
gametime | number | Unix timestamp in milliseconds when W3Booster observed the upgrade. |
researchStart? | string | ISO-8601 timestamp on researching upgrades. |
researchFinish? | string | ISO-8601 estimated completion timestamp. |
overlay:readOverlayRuntimeState
| Field | Type | Description |
|---|---|---|
chatbarOpen? | boolean | Whether the in-game chat bar is open. |
hudScale? | number | CSS multiplier normalized from 0.5–1.0. |
matchScore? | { wins: number; losses: number } | User-controlled nested match score. |
teamColors? | boolean | Native versus simplified team-color preference. |
ApplicationState<TSettings>
| Field | Type | Description |
|---|---|---|
clientId | string | The current app’s public immutable identifier. |
settings | DeepReadonly<TSettings> | Resolved per-user settings for this app only. |
surface? | 'application' | 'streamOverlay' | 'ingameOverlay' | The surface W3Booster launched. |
development? | boolean | Whether the owner’s temporary local override is active. |
Schema-dependent A settings field can declare requiresPlan: 'pro'. That prevents Basic users from changing the setting; it is an app-settings control, not a data entitlement. The resolved default or previously saved value can still be delivered.
? fields are conditional because no match is active, the source did not provide the value, the app lacks that scope, the current surface does not use it, or server-side privacy filtering applies. Only the hero and upgrade branches have a platform data-plan gate today.Events and selectors
Observe the view model you need.
Use state subscriptions for complete rendering, watch() for one derived value, and domain events for meaningful changes after the initial snapshot.
const stopClock = client.state.watch(
state => state?.match.gameTime ?? null,
seconds => drawClock(seconds)
);
client.on('match.started', ({ match }) => showMatch(match));
client.on('player.resources.changed', ({ player, resources }) => {
updateEconomy(player.id, resources);
});
client.on('hero.inventory.changed', ({ player, inventory }) => {
updateInventory(player.id, inventory);
});The initial snapshot emits state.ready and state.changed. It does not synthesize match.started for a match that was already running.
Pure selectors
import {
broadcasterPlayer,
groupPlayersByTeam,
matchScore,
playerRelationship
} from '@w3booster/sdk/selectors';
const broadcaster = broadcasterPlayer(state.match, state.players);
const teams = groupPlayersByTeam(state.players);
const score = matchScore(state);Selectors are framework-free and never mutate state. The namespace also includes stable fallbacks, identity helpers, broadcaster-first teams, relationships, inventory, resources, upgrades, and overlay runtime.
Standard-game data and assets
Import only the Warcraft knowledge you use.
Rules, icons, and cooldown metadata have separate entry points. This keeps lightweight apps small while preserving a combined objects namespace for compatibility.
import * as game from '@w3booster/sdk/standard-game';
import * as icons from '@w3booster/sdk/standard-game/icons';
import * as cooldowns from '@w3booster/sdk/standard-game/cooldowns';
const heroIcon = icons.heroIconUrl(hero, {
graphics: state.match.isReforged ? 'reforged' : 'classic'
});
const cooldown = cooldowns.abilityCooldown(ability, state.match.gameTime);
const clock = game.formatGameTime(state.match.gameTime);
const progress = game.heroExperienceState(hero.experience);The standard-game namespace covers race labels, modes, player colors, statistics selection, game-time formatting, day/night state, hero progression, health/mana ratios, observer ordering, and presentation colors. Hosted Classic and Reforged icons resolve from the versioned static asset catalog; artwork is not bundled with npm.
Typed settings
Define settings once. Keep UI and types together.
Build the schema in W3Booster and let the client render consistent controls. The SDK can generate a checked-in TypeScript binding with the exact schema, defaults, scopes, client ID, and a managed application runtime.
npx w3booster-settings init app_your_id
npm run w3booster:sync
npm run w3booster:checkCommit src/w3booster.generated.ts. This keeps editor types and offline builds deterministic while making schema changes visible in code review.
import { w3boosterApp } from './w3booster.generated';
const runtime = w3boosterApp.createRuntime({ retry: true });
runtime.lifecycle.subscribe(snapshot => {
renderMatch(snapshot.state, { fresh: snapshot.isSynchronized });
renderSettings(snapshot.settings);
renderHostActions(snapshot.host);
});
await runtime.start();
await runtime.stop();The managed runtime resolves partial user settings over database defaults and publishes settings atomically with state and host capabilities. Lower-level tools remain available from @w3booster/sdk/settings.
Host actions
Ask the workspace. Await the result.
Embedded app surfaces can open or close windows, change Match Vision scores, persist typed settings, report their height, and issue app-specific commands. Every asynchronous action waits for a host acknowledgement.
import { canUseHostCapability } from '@w3booster/sdk';
client.host.lifecycle.subscribe(host => {
setCompactEnabled(canUseHostCapability(host, 'window:open'));
});
await client.host.openWindow({
path: '?view=compact',
width: 520,
height: 620
});
const saved = await client.host.setSetting(
'observer.layout',
'wide',
{ signal, timeout: 3000 }
);Use host.can(capability) for imperative code or the reactive host lifecycle for UI. Capability discovery distinguishes pending, known, legacy, and unavailable hosts. Action cancellation raises AbortError; rejected execution raises HostActionError; missing or timed-out hosts raise ConnectionError.
Framework integration
Use the store your framework already understands.
The SDK has no frontend framework dependency. Its immediate stores map directly to Angular signals and RxJS; a small React subpath implements the complete useSyncExternalStore contract.
@w3booster/sdk/reactconst store = createReactStore(client.lifecycle, {
getServerSnapshot: () => ({
status: 'idle', state: null,
isSynchronized: false, error: null
})
});
const snapshot = useSyncExternalStore(
store.subscribe,
store.getSnapshot,
store.getServerSnapshot
);
signal()const lifecycle = signal(client.lifecycle.get());
client.lifecycle.subscribe(
snapshot => lifecycle.set(snapshot),
{ signal: lifetime.signal }
);
Errors and diagnostics
Separate startup failure from runtime issues.
Catch permanent startup errors around start(). Subscribe to structured issue events for recoverable connection, protocol, recorder, and listener problems that should not turn healthy match data into a failed UI.
import {
classifyW3BoosterError,
createClient
} from '@w3booster/sdk';
const client = createClient({ clientId: 'your_app_id' });
client.on('issue', issue => {
console.warn(issue.source, issue.recoverable, issue.error);
});
try {
await client.start();
} catch (error) {
const info = classifyW3BoosterError(error);
switch (info.kind) {
case 'permission': showOpenFromW3Booster(); break;
case 'connection': showOffline(info.code); break;
case 'abort': break;
default: report(info.error);
}
}Open the installed, enabled app from W3Booster or renew its local session.
Inspect the stable code such as UNAVAILABLE, CONFIGURATION, or STATE_TIMEOUT.
Use the code and details. Recoverable invalid data resynchronizes; permanent incompatibility closes the stream.
The authenticated workspace received an action but rejected its execution.
Publish
Private first. Reviewed before discovery.
- Complete the store listingAdd a clear description, surfaces, screenshots, source or homepage links, and requested scopes.
- Test every surfaceCheck application, stream, and in-game behavior; disabled states; reconnects; and missing optional data.
- Request reviewW3Booster reviews the record, hosted behavior, scope use, and user experience.
- Make it publicAfter approval, users can discover and install it from the App Store. Metadata edits do not require another review.
Installation and enabling are separate platform states. Disabling preserves the app in the user’s library; uninstalling removes the grant. Revocation closes affected streams immediately.
Package reference
Focused entry points, one compatibility policy.
@w3booster/sdkClient, lifecycle, hydrated data model, events, host facade, errors.
@w3booster/sdk/selectorsPure match, player, team, resources, score, and identity derivations.
@w3booster/sdk/appGenerated application bindings and managed application runtimes.
@w3booster/sdk/settingsSchema validation, defaults, resolution, and binding generation.
@w3booster/sdk/standard-gameLightweight Warcraft III rules and presentation helpers.
…/standard-game/iconsClassic/Reforged asset URLs and match-aware resolvers.
…/standard-game/cooldownsAbility cooldown metadata and state derivation.
@w3booster/sdk/assetsHosted shared-asset and country-flag URL helpers.
@w3booster/sdk/reactDependency-free adapters for React external stores and selectors.
@w3booster/sdk/testingDemo transports and custom transport types for tests.
@w3booster/sdk/compositor authenticates the stable browser source and loads enabled overlay apps. Ordinary applications do not import it and never receive browser-source credentials.