# Changelog ## 2.0.0 Breaking change — major bump, required by the backend environments release. Every project now has exactly two environments, `staging` and `prod`, and the SDK key passed as `projectKey` decides which one the player belongs to. The environment never appears in the client API: it is resolved at login and carried inside the access and refresh tokens. Tokens issued before this release have no environment claim and are rejected with 401, so the first call after the backend upgrade refreshes, fails, clears the token store and emits `'signed-out'` to every `onAuthStateChange` listener. Log the player in again with `client.auth.loginWithDevice()` / `loginWithCustom()`. Quests, scenarios and offers are addressed by their slug instead of their id, because ids differ between staging and prod while slugs are stable. Renamed accordingly: `Quest.id` is now `Quest.slug`, `client.quests.claim()` takes a quest slug, `reportProgress()` resolves to the slugs of the completed quests (`ReportQuestProgressResponse.completedQuestSlugs`), `client.stores.purchase(storeSlug, offerSlug, options?)` takes an offer slug and `OfferHandle` carries a `slug` alongside its `id`, `QuestMetrics.purchaseOffer(offerSlug)` builds its metric from the offer slug, and every scenario-scoped type exposes `scenarioSlug` instead of `scenarioId` — `PendingEffect`, `ScenarioCompletedEffect`, `ScenarioFailedEffect`, the battle pass requests and `client.battlePass.getProgress(scenarioSlug, nodeId)`. `offer.buy()` is unchanged; it now binds the slug for you. Leaderboards, items and stores already used slugs and are untouched. Also shipped here, previously committed but never published: the effects client reconciles against every `GET /sdk/v1/scenarios/pending` response, so a run that disappears server-side (finished elsewhere, expired after a promote) now emits `onScenarioCompleted` instead of lingering; and `run_not_active` joins `unknown_run` and `run_expired` as a terminal rejection that drops the run and emits `onScenarioFailed`. ## 1.0.0 - Scenario execution moved server-side. The SDK no longer walks a local DAG or persists plan state to IndexedDB. - Removed `RudderClientOptions.runtime.planStateStore` and the `PlanStateStore` type. - `GET /sdk/v1/scenarios/pending` is polled on login, on a ~30s heartbeat, and at each effect `waitDeadline`. Completions POST `/sdk/v1/scenarios/callback`; the response may carry the next `PendingEffect`. - Scenario `remote_config_override` nodes no longer emit `onConfigChanged` (the server applies the override). The `ConfigChangedEffect` type and `onConfigChanged` subscription remain. ## 0.6.0 - `LeaderboardSession.claim()` / effect `claim()` completes the leaderboard node with handle `onClaim`. The server matches live rank to an authored place and continues from that place (Grant Reward and/or In-App Message). - `rewardClaimed()` is a deprecated alias for `claim()` and will be removed in the next SDK version. - `rank_not_eligible` on Claim leaves the session open (retry Claim or End); it no longer fails the run. ## 0.5.1 - `QuestMetrics` / `reportProgress`: custom free-text metrics no longer progress quests. Report a released catalog counter slug instead. `purchaseOffer` / `purchaseItem` helpers are unchanged (server-side shop fan-out). ## 0.5.0 - `client.auth.loginWithCustom({ customData, region?, language?, nickname? })` — custom webhook auth, same token + runtime start as `loginWithDevice`. - `QuestMetrics.purchaseOffer` / `purchaseItem` helpers for the shop purchase metric format. - Typecheck against regenerated models: `listQuests` no longer takes a body, battle-pass `track` is `'free' | 'premium'`, scenario run status has no `unknown_run`. ## 0.4.0 - Fixed `BattlePassLevelSession.level` reading node data key `level` — the admin editor writes `levelNumber`, so tiers always reported `0`. The session now reads `levelNumber`, matching the editor and server validation. - UGC support removed from the generated wire types (`src/generated/ugc.ts` deleted by apigen); no UGC surface was ever exposed by this SDK. - Generated API types regenerated from the gateway openapi spec, adding the new platform operations. ## 0.3.0 Breaking changes — the package was aligned with the Rudder SDK glossary and the regenerated wire types (`src/generated`, apigen). No compatibility shims are provided. ### Auth - `client.auth.loginViaDevice(region, language, nickname?)` replaced by `client.auth.loginWithDevice(options?: { region?, language?, nickname? })`. Default region is now `'global'` (was `'en'`); default language stays `'en'`. - New `client.auth.onAuthStateChange(cb)` — fires immediately with the current state, then on every `'signed-in' | 'signed-out'` transition (login, logout, and unrecoverable session expiry in the transport). - New `client.auth.isAuthenticated`. ### Client configuration - `tokenStore` in `RudderClientOptions` is now optional. Default: localStorage-backed store with a silent in-memory fallback where localStorage is unavailable (SSR, private mode). New `createDefaultTokenStore()` export. - Invalid client options (`baseUrl` / `projectKey` missing) now throw `RudderError` with `code: 'sdk/invalid-options'` instead of a plain `Error`. - New `onEffectError` option — called when an effect handler throws (default: `console.error`); previously such errors were swallowed silently. ### Renames - `client.config` → `client.remoteConfig` (canonical glossary name). - `client.battlepass` → `client.battlePass`; `BattlepassService` → `BattlePassService`. - Effects: `onBattlepass` / `BattlepassEffect` → `onBattlePass` / `BattlePassEffect`; `onBattlepassLevel` / `BattlepassLevelEffect` → `onBattlePassLevel` / `BattlePassLevelEffect`. - Generated types: `SdkQuest` → `Quest`; `*Battlepass*` request/response types → `*BattlePass*`. - Internal transport `sendAsync` → `request` (not part of the public surface). ### Leaderboards - Removed `LeaderboardsService.getRanking(slug, limit)` and `LeaderboardsService.submitScore(slug, score)`. Single path: `client.leaderboards.findBySlug(slug)` → `handle.list(limit?)` / `handle.submit(score)`. ### Errors - `RudderNetworkError.inner` → standard `Error.cause`. - `RudderHttpError.code` is typed as `RudderErrorCode | (string & {})` (generated union of server error codes, plus room for unknown strings). - New exports: `RudderErrorCode` (type), `RudderErrorCodes` (constants), `SDK_ERROR_INVALID_OPTIONS`, `RudderErrorCodeLike` (type). ### Public surface - The barrel no longer exports `getOrCreateDeviceId`, domain classes (`PlayerDomain`, …) or service constructors (`AuthService`, …) as values — they remain available as types. Instances live on the client. - `SubmittedBy` is no longer re-exported (UGC is unsupported on web). ### Bundle - The scenario engine and the IndexedDB plan store are loaded lazily (dynamic import) on first login / first runtime access — a thin client never pulls the scenario machinery into the initial chunk. - The package now ships both ESM (`dist/index.js`) and CJS (`dist/index.cjs`) builds with matching `exports` entries.