Files
rudder-js-sdk/skills/rudder-web-sdk/SKILL.md
T
edmand46 8753239fbd
CI / check (push) Successful in 55s
CI / publish (push) Has been skipped
Add agent skill (SKILL.md + per-domain reference)
2026-08-29 11:46:20 +03:00

6.5 KiB

name, description
name description
rudder-web-sdk Use when working with the Rudder TypeScript/JavaScript SDK (@rudder/js-sdk) — the browser/player-facing SDK for the Rudder LiveOps platform. Covers client setup, device/custom auth, observable domains (player, inventory, catalog, stores, remote config, storage), leaderboards, quests, battle pass, scenario effects, and error handling. Load this whenever code imports from @rudder/js-sdk or RudderClient appears.

Rudder Web SDK (@rudder/js-sdk)

Browser-facing player SDK for the Rudder LiveOps platform. Source of truth: liveops-web-sdk/src (generated wire types in src/generated come from the gateway's apigen — never edit them by hand).

Install

Published to a private registry, 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/js-sdk

ESM + CJS + .d.ts; type: module; zero runtime dependencies.

Init

import { RudderClient } from '@rudder/js-sdk';

const client = new RudderClient({
  baseUrl: 'https://api.rudder.build',   // required
  projectKey: 'your-project-key',        // required
  // tokenStore?: TokenStore              — default: localStorage, in-memory fallback
  // requestTimeoutMs?: number            — default 10000
  // syncIntervalMs?: number              — revision poll, default 30000 (±20% jitter)
  // onEffectError?: (error) => void      — default console.error
  // runtime?: { planStateStore?, loginEvent? }  — advanced, see reference/scenarios.md
});

client is generic: RudderClient<TConfig extends Record<string, unknown>> types client.remoteConfig.get(). Missing baseUrl/projectKey throws RudderError with code: 'sdk/invalid-options' from the constructor.

Call client.dispose() on unmount/HMR to stop the sync poll, wait timers, and drop cached state.

Auth essentials

await client.auth.loginWithDevice({ region, language, nickname }); // device id auto-generated/persisted
await client.auth.loginWithCustom({ customData, region, language, nickname });
client.auth.logout();
client.auth.isAuthenticated;                       // boolean
client.auth.onAuthStateChange(cb);                 // fires immediately, returns unsubscribe

Tokens are saved to the TokenStore automatically. The transport injects Authorization: Bearer <token>, retries GETs, and single-flight refreshes on 401; a failed refresh clears tokens and emits signed-out. Details: reference/auth.md.

Client surface (all domains that exist)

Every member below is a property on RudderClient. There is no UGC, wallet service, or standalone economy service in this SDK — wallets live on client.player.data.wallets, and purchases go through client.stores.

Area Access Kind
Auth client.auth service
Player profile + wallets client.player observable SyncedState<PlayerProfile>
Inventory (catalog-merged) client.inventory observable SyncedState<InventoryItem[]>
Catalog client.catalog observable SyncedState<Map<string, CatalogItem>>
Stores / purchases client.stores + client.stores.purchase(slug, offerId, opts?) observable SyncedState<ShopHandle[]>
Remote config client.remoteConfig + .get(key, default?) observable, typed
Player storage client.storage + .save(items) / .delete(type) observable + mutations
Project storage client.projectStorage + .save(items) observable + mutation
Leaderboards client.leaderboards.findBySlug(slug) service → cached handle
Battle pass client.battlePass plain service (no live sync)
Quests client.quests plain service (no live sync)
Scenario effects client.effects.on* event subscriptions

Observable domains — the shared pattern

player, catalog, inventory, remoteConfig, storage, projectStorage, and stores all extend SyncedState<T>:

  • .data: T | undefined, .status: 'idle' | 'loading' | 'ready' | 'error', .error?: Error
  • onChange(cb: (snapshot: SyncedSnapshot<T>) => void): () => void — fires immediately with the current snapshot; maps onto React useSyncExternalStore
  • load(): Promise<T> — deduplicated, no-op when ready
  • reload(): Promise<T> — forced refetch

remoteConfig, player, stores, and catalog are warmed once at login; inventory, storage, and projectStorage load on first use. All observable domains are then kept fresh by a revision poll every 30 s (±20% jitter); polling pauses while the tab is hidden. Mutations (purchases, storage writes, scenario callbacks) invalidate affected domains immediately. Call reload() when you need a freshness guarantee.

leaderboards, battlePass, and quests are NOT observable — refetch explicitly after mutations.

Errors

All SDK errors extend RudderError (optional machine-readable code):

  • RudderNetworkError — fetch failed / timeout (error.cause holds the original)
  • RudderHttpError — non-2xx, carries status, statusText, body, code
  • RudderAuthError extends RudderHttpError — 401 after failed refresh; tokens already cleared, signed-out already emitted
  • RudderError with code: 'sdk/invalid-options' (SDK_ERROR_INVALID_OPTIONS) — constructor validation

Server error codes (RudderErrorCodes, from src/generated/errors.ts): early_completion, forbidden, level_not_reached, node_not_active, objectives_incomplete, run_expired, run_not_active, scenario_not_active, unknown_run. Compare with error.code === RudderErrorCodes.runExpired.

Reference files