142 lines
6.4 KiB
Markdown
142 lines
6.4 KiB
Markdown
---
|
|
name: rudder-web-sdk
|
|
description: 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/google/apple/custom auth, identity linking, observable kernel domains (player, catalog, storage), modules.call, resources(slug), 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
|
|
`liveops-backend/apigen` — never edit them by hand).
|
|
|
|
2.0 kernel surface: auth, player (wallets), catalog currencies, storage,
|
|
project storage, revision sync, `client.modules.call(module, fn, args)`,
|
|
and `client.resources(slug)`. Module-specific methods (battle pass, quests,
|
|
leaderboards, stores, inventory, remote config, scenarios) are gone.
|
|
|
|
## 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/
|
|
```
|
|
|
|
```bash
|
|
npm install @rudder/js-sdk
|
|
```
|
|
|
|
ESM + CJS + `.d.ts`; `type: module`; zero runtime dependencies.
|
|
|
|
## Init
|
|
|
|
```ts
|
|
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)
|
|
});
|
|
```
|
|
|
|
Missing `baseUrl`/`projectKey` throws `RudderError` with
|
|
`code: 'sdk/invalid-options'` from the constructor.
|
|
|
|
Call `client.dispose()` on unmount/HMR to stop the sync poll and drop cached
|
|
state.
|
|
|
|
## Auth essentials
|
|
|
|
```ts
|
|
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);
|
|
```
|
|
|
|
Linked identities are listed on the profile: `client.player.data.identities`
|
|
(`PlayerProfileIdentity { provider, subject, createdAt }`).
|
|
|
|
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](reference/auth.md).
|
|
|
|
## Client surface
|
|
|
|
| Area | Access | Kind |
|
|
|---|---|---|
|
|
| Auth | `client.auth` | service |
|
|
| Player profile + wallets | `client.player` | observable `SyncedState<PlayerProfile>` |
|
|
| Catalog currencies | `client.catalog` | observable `SyncedState<Map<string, CatalogCurrency>>` |
|
|
| Player storage | `client.storage` + `.save(items)` / `.delete(type)` | observable + mutations |
|
|
| Project storage | `client.projectStorage` + `.save(items)` | observable + mutation |
|
|
| Modules | `client.modules.call(module, fn, args?)` | `CallModuleFunctionClientResponse` (`{ result }`) |
|
|
| Resources | `client.resources(slug)` | `list` / `get` / `create` / `update` / `delete` |
|
|
|
|
Wallets live on `client.player.data.wallets`. Game features are installed
|
|
modules, not SDK services (first-party modules: items, inventory, reward,
|
|
remote_config, leaderboards, quests, store, battlepass). Call them with
|
|
`client.modules.call('my_module', 'hello', { ... })` and read their rows with
|
|
`client.resources(slug)`. Details: [reference/modules.md](reference/modules.md),
|
|
[reference/resources.md](reference/resources.md).
|
|
|
|
## Observable domains — the shared pattern
|
|
|
|
`player`, `catalog`, `storage`, and `projectStorage` 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
|
|
|
|
`player` and `catalog` are warmed once at login; `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. Storage mutations invalidate their domain immediately. Call `reload()`
|
|
when you need a freshness guarantee.
|
|
|
|
## 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
|
|
|
|
The platform error codes are `forbidden` and `row_referenced`
|
|
(`src/generated/errors.ts`, not exported from the package entry); compare
|
|
`error.code === 'forbidden'`.
|
|
|
|
`client.modules.call` resolves to `{ result }` only; console output and the
|
|
kernel call log never reach players. A module business error rejects with
|
|
`RudderHttpError` whose `status` is 422 and whose `code` is the module's own
|
|
code (the body is `{ error, code, requestId }`). Module codes are open strings
|
|
with no generated constants, so compare against the codes the module
|
|
documents. A module trap is a 500 and a timeout a 504, both without details.
|
|
|
|
## Reference files
|
|
|
|
- [reference/auth.md](reference/auth.md) — login flows, options, token store, session lifecycle
|
|
- [reference/player.md](reference/player.md) — profile + wallets (`PlayerProfile`, `Wallet`)
|
|
- [reference/storage.md](reference/storage.md) — player + project storage, limits
|
|
- [reference/modules.md](reference/modules.md) — `modules.call`, response, module errors
|
|
- [reference/resources.md](reference/resources.md) — `resources(slug)` row operations
|