Files
rudder-js-sdk/skills/rudder-web-sdk/SKILL.md
T

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: the package source and its type declarations (wire types in src/generated are generated; never edit them by hand).

0.2.1 covers only the kernel: auth, player, catalog, storage, module calls and background 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 Rudder package 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?: Error
  • onChange(cb: (snapshot: SyncedSnapshot<T>) => void): () => void: fires immediately with { status, value, error }; maps onto React useSyncExternalStore
  • load(): Promise<T>: deduplicated, no-op when ready
  • reload(): 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.cause holds the original)
  • RudderHttpError: non-2xx, carries status, statusText, body, code
  • RudderAuthError extends RudderHttpError: 401 after a failed refresh; tokens already cleared, signed-out already emitted
  • RudderModuleError<C> extends RudderHttpError: a module call returned 422 { error, code, requestId }; exposes code: C, message, requestId
  • RudderError with code: '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