Steam
Steamworks integration — what exists, what's stubbed, the launch checklist
The game ships on Steam (native) with a browser build alongside — so Steam is treated as one distribution channel, never the source of truth. Everything Steam-specific is isolated in apps/api/src/steam.ts.
What works today
createSteamClient(env) returns a client that mirrors achievement unlocks via ISteamUserStats/SetUserStatsForGame. Without credentials it's a logged no-op, so calling code never branches:
[steam] disabled — would unlock FIRST_STEPS for 7656119… (set STEAM_WEB_API_KEY + STEAM_APP_ID)Reality check: there are no Steam webhooks
Steam does not push events for game happenings. The only callback-style API is for microtransactions (ISteamMicroTxn), and even that is request/response. So the integration direction is:
- We push to Steam: achievement unlocks (done), stats (same endpoint, when needed).
- We poll from Steam: wishlist totals, review counts, player counts — a scheduled job hitting the partner Web API, feeding
#dev-log. Not built yet; small and additive when wanted.
Launch checklist
- Steamworks account + app id — partner.steamgames.com; put the app id in
STEAM_APP_ID. - Publisher Web API key — Steamworks → Users & Permissions → Manage Groups → your group → Create WebAPI Key. This is a publisher key (server-to-server, works with
partner.steam-api.com), not a personal key from steamcommunity.com/dev. Store asSTEAM_WEB_API_KEY— server env only, never the client. - Define achievements — Steamworks → Stats & Achievements: for each entry in
packages/shared/src/achievements.ts, create an achievement whose API Name equals thekey(FIRST_STEPS, …). Names/descriptions/icons live in Steamworks per locale; ourname/descriptionare the canonical English strings. - Sign in with Steam — better-auth generic provider against Steam OpenID 2.0, storing steamId64 as
account.accountIdwithproviderId: "steam". Mirroring already keys off exactly this — no other code changes. - In-game unlocks — the Rust client also calls the Steamworks SDK locally for the instant overlay popup; the API call is what makes it canonical and cross-platform.
Multiplayer, eventually
Steam networking/lobbies are a client-side SDK concern in the Rust repo. This backend's role stays identity + meta-services (architecture notes).