143 lines
6.0 KiB
Markdown
143 lines
6.0 KiB
Markdown
---
|
|
name: rudder-web-sdk
|
|
description: 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/
|
|
```
|
|
|
|
```bash
|
|
npm install @rudder/sdk
|
|
```
|
|
|
|
ESM + CJS + `.d.ts`; `type: module`; zero runtime dependencies.
|
|
|
|
## Init
|
|
|
|
```ts
|
|
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
|
|
|
|
```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);
|
|
```
|
|
|
|
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](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`, read-only | `SyncedState<GetStorageResponse>` |
|
|
| Modules | `client.modules.call<T>(module, fn, args?, { moduleVersion? })` | resolves to `result` as `T` |
|
|
|
|
## Module calls through generated clients
|
|
|
|
```bash
|
|
RUDDER_URL=... RUDDER_TOKEN=... RUDDER_PROJECT=... \
|
|
rudder client generate --lang ts --out src/rudder.modules.ts [--environment staging|prod]
|
|
```
|
|
|
|
```ts
|
|
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](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
|
|
|
|
- [reference/auth.md](reference/auth.md): login flows, options, token store, session lifecycle
|
|
- [reference/player.md](reference/player.md): profile, balances, items
|
|
- [reference/storage.md](reference/storage.md): player storage, limits
|
|
- [reference/modules.md](reference/modules.md): generated clients, `modules.call`, idempotency, retries, errors
|