6.1 KiB
name, description
| name | description |
|---|---|
| rudder-web-sdk | Use when working with the Rudder TypeScript/JavaScript client SDK (@rudder/sdk) for web games. Covers createClient, device/google/apple/custom auth, identity linking, state objects (player with balances and items, catalog, storage), module calls through clients generated by `rudder client generate`, idempotent retries, and error handling. Load this whenever code imports from @rudder/sdk or a generated rudder.modules.ts. |
Rudder Web SDK (@rudder/sdk)
Client SDK for web games on the Rudder LiveOps platform. Source of truth:
liveops-web-sdk/src (wire types in src/generated come from
liveops-backend/apigen; never edit them by hand).
0.1.0 covers only the kernel: auth, player, catalog, storage, module calls and
internal revision sync. Game features are installed modules, reached through a
typed client generated from their manifests. There is no resources(slug) and
no projectStorage; game-facing configuration comes from modules such as
remote_config.
Install
Published to the Gitea registry at hub.rudder.build, not npmjs. Point the
@rudder scope at it in .npmrc (anonymous read, no token):
@rudder:registry=https://hub.rudder.build/api/packages/rudder/npm/
npm install @rudder/sdk
ESM + CJS + .d.ts; type: module; zero runtime dependencies.
Init
import { createClient } from '@rudder/sdk';
const client = createClient({
projectKey: 'your-project-key', // required; selects staging or prod
// baseUrl?: string — default 'https://api.rudder.build'
// tokenStore?: TokenStore — default: localStorage, in-memory fallback
// appVersion?: string — sent with platform 'web' on login/refresh
// requestTimeoutMs?: number — default 10000
// syncIntervalMs?: number — revision poll, default 30000 (±20% jitter)
});
A missing projectKey throws RudderError with
code: 'sdk/invalid-options'. Call client.dispose() on unmount/HMR to stop
the sync poll and drop cached state.
Auth essentials
await client.auth.loginWithDevice({ region, language, nickname }); // device id auto-generated/persisted
await client.auth.loginWithGoogle({ idToken, region, language, nickname });
await client.auth.loginWithApple({ idToken, region, language, nickname });
await client.auth.loginWithCustom({ customData, provider?, region, language, nickname });
await client.auth.linkWithGoogle(idToken);
await client.auth.linkWithApple(idToken);
await client.auth.linkWithCustom({ customData, provider? });
await client.auth.unlinkIdentity(provider); // 'device' | 'google' | 'apple' | 'custom' | 'custom:<name>'
client.auth.logout();
client.auth.isAuthenticated;
client.auth.onAuthStateChange(cb);
Tokens are saved to the TokenStore automatically. The transport injects
Authorization: Bearer <token> and single-flight refreshes on 401; a failed
refresh clears tokens and emits signed-out. Details:
reference/auth.md.
Client surface
| Area | Access | Kind |
|---|---|---|
| Auth | client.auth |
service |
| Player | client.player (player, identities, balances, items) |
SyncedState<PlayerProfile> |
| Catalog currencies | client.catalog |
SyncedState<Map<string, CatalogCurrency>> |
| Player storage | client.storage + .save(type, data) / .delete(type) |
SyncedState<GetStorageResponse> + mutations |
| Modules | client.modules.call<T>(module, fn, args?, { moduleVersion? }) |
resolves to result as T |
Module calls through generated clients
RUDDER_URL=... RUDDER_TOKEN=... RUDDER_PROJECT=... \
rudder client generate --lang ts --out src/rudder.modules.ts [--environment staging|prod]
import { modules } from './rudder.modules';
const m = modules(client);
await m.leaderboards.submit({ slug: 'weekly', score: 120 });
const top = await m.leaderboards.top({ slug: 'weekly', limit: 10 });
The generated file is a factory over client.modules.call, with argument and
result types, and a <Module><Fn>Error code union per function. Regenerate
and commit it when installed modules change. Details:
reference/modules.md.
State objects: the shared pattern
player, catalog and storage extend SyncedState<T>:
.value: T | undefined,.status: 'idle' | 'loading' | 'ready' | 'error',.error?: ErroronChange(cb: (snapshot: SyncedSnapshot<T>) => void): () => void: fires immediately with{ status, value, error }; maps onto ReactuseSyncExternalStoreload(): Promise<T>: deduplicated, no-op when readyreload(): Promise<T>: forced refetch
player and catalog are warmed at login; storage loads on first use. A
revision poll (GET /sdk/v1/sync, keys profile, catalog, storage) runs
every 30 s (±20% jitter), pauses while the tab is hidden, and reloads the
states whose revision grew. Storage mutations invalidate immediately. Call
player.reload() after a module call that changes balances or items when
you need fresh values right away.
Errors
All SDK errors extend RudderError (optional machine-readable code):
RudderNetworkError: fetch failed or timed out (error.causeholds the original)RudderHttpError: non-2xx, carriesstatus,statusText,body,codeRudderAuthError extends RudderHttpError: 401 after a failed refresh; tokens already cleared,signed-outalready emittedRudderModuleError<C> extends RudderHttpError: a module call returned 422{ error, code, requestId }; exposescode: C,message,requestIdRudderErrorwithcode: 'sdk/invalid-options'(SDK_ERROR_INVALID_OPTIONS)
Compare error.code with string literals. A module trap is a 500 and a
timeout a 504, both without details.
Reference files
- reference/auth.md: login flows, options, token store, session lifecycle
- reference/player.md: profile, balances, items
- reference/storage.md: player storage, limits
- reference/modules.md: generated clients,
modules.call, idempotency, retries, errors