10 KiB
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 you configure 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 stored tokens and raises
AuthService.AuthStateChanged with RudderAuthState.SignedOut. Log the player
in again with Auth.LoginWithDeviceAsync / LoginWithCustomAsync.
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, QuestsService.ClaimAsync takes a
quest slug, ReportProgressAsync returns the slugs of the completed quests
(ReportQuestProgressResponse.CompletedQuestSlugs), StoresService.PurchaseAsync
takes an offer slug and Offer carries a Slug, QuestMetrics.PurchaseOffer
builds its metric from the offer slug, and every scenario-scoped type exposes
ScenarioSlug instead of ScenarioId — PendingEffect, the effect objects,
ScenarioCompletedEffect, ScenarioFailedEffect, the battle pass requests and
BattlePassService.GetProgressAsync. Leaderboards, items and stores already
used slugs and are unchanged.
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
Breaking change — major bump. The local scenario engine is replaced by a server-driven effects client; the realtime websocket client is removed.
Removed
- Local scenario runtime:
PlanRun,ExecutionPlanwalking, node sessions (NotificationSession,StoreOfferSession,LeaderboardSession,WaitSession,QuestSession,BattlePassSession,BattlePassLevelSession,ConfigChangedSession),RespondAsync/Respond,RestoreAsync,Clear,ActiveRuns,IsRunning,CurrentNodeId,OnConfigChanged. RudderClientOptions.PlanStateStore/IPlanStateStoreandIPlanScheduler— no local plan persistence or delayed plan work.RealtimeService(client.Realtime),RudderClientOptions.RealtimeUrl/RealtimeTransportFactory,IRealtimeTransport/IRealtimeTransportFactory.
Changed (breaking)
client.Scenariois a trigger only:TriggerAsync(eventName)returnsTask(not started plans). Returned pending effects are ingested intoclient.Effects.- Subscribe to
client.Effects.On*instead ofclient.Scenario.On*. Sessions are now effect objects (NotificationEffect,StoreOfferEffect, …). Complete them with the methods on the effect (DoneAsync,PurchaseAsync/DeclineAsync,EndAsync/ClaimAsync, …). client.Update(deltaTime)is still required every frame — it now pumps the effects client (30sGET /sdk/v1/scenarios/pendingheartbeat + wait-deadline checks), not a local DAG or a websocket.- After login (or when constructed with a stored access token), the next
Updatefetches pending effects. There is nologinEventoption; trigger login-gated scenarios yourself.
Migration
| Before | After |
|---|---|
client.Scenario.OnNotification (and other On*) |
client.Effects.OnNotification (same event names) |
NotificationSession / StoreOfferSession / … |
NotificationEffect / StoreOfferEffect / … |
session.CompleteAsync() / RespondAsync("output") |
effect.DoneAsync() (and the matching method on each effect) |
RudderClientOptions.PlanStateStore + RestoreAsync |
gone — server owns run state; pending fetch after login + heartbeat |
client.Realtime |
gone |
client.Update(deltaTime) |
still required (effects pump) |
0.4.0
- Generated DTOs live under
Models/(RudderSdk.Core.Models). Wire fields are nullable.ListQuestsRequestis gone;Quests.ListAsyncPOSTs with no body.BoundaryNode.WaitDeadlineisDateTimeOffset?. LeaderboardSession.ClaimAsync/Claimcomplete the leaderboard node with handleonClaim. The server matches live rank to an authored place.RewardClaimedAsync/RewardClaimedare obsolete aliases and will be removed in the next SDK version.rank_not_eligibleon Claim leaves the session open (retry Claim or End); it no longer fails the run.
0.3.0
Removed
- UGC surface:
UgcService(client.Ugc), the generatedRudderSdk.Core.Models.UgcDTOs,IUploadTransportandRudderClientOptions.UploadTransport. The server no longer exposes the UGC endpoints.
Changed (breaking)
BattlePassServicesimple overloads sent empty scenario/node ids and always failed server-side. Battle pass state is tied to a scenario battle pass node, so the public API now mirrors the web SDK:GetProgressAsync(scenarioId, nodeId)and the request-DTO overloadsAddXpAsync,ClaimRewardAsync,PurchasePremiumAsync(carryingScenarioId/NodeId/RunId) are public; the internal request overloads are gone.BattlePassSessionnow exposes the bound battle pass operations (GetProgressAsync,AddXpAsync(source, amount),ClaimRewardAsync(level, track),PurchasePremiumAsync()— crossesonPremiumPurchaseon success), mirroring the web SDK session.BattlePassLevelSession.CompleteAsync/Completerenamed toClaimAsync/Claim; newLevelproperty reads thelevelNumbernode data key.- Unsupported scenario node types now fail the run (
OnScenarioFailed) instead of stalling silently. - Scenario counter updates no longer read a continuation plan from the
response (the server stopped returning one); when the server reports the
objective completed, the node crosses
onComplete.
Fixed
- A failed scenario counter update no longer fails the run; the error is logged and the node stays active.
0.2.0
Added
QuestsService(client.Quests) withListAsync/ClaimAsync.AuthService.LoginWithDeviceAsync(region, language, nickname?)andAuthService.RefreshAsync();AuthStateChangedevent (RudderAuthState.SignedIn/SignedOut).- Session pipeline: single-flight token refresh plus one transparent
retry-on-401 for every API call; failed refresh clears tokens and reports
SignedOut. HttpClientTransport— defaultSystem.Net.Http.HttpClient-based transport.RudderClientOptions.Transportis now optional, as areTokenStore(InMemoryTokenStore) andDeviceIdProvider(GuidDeviceIdProvider).- Typed exceptions:
RudderAuthException(401),RudderNotFoundException(404),RudderRateLimitException(429),RudderNetworkException(network/timeout). All carryRequestIdfrom the server error payload. StorageService.ListAllAsyncandUgcService.ListAllAsync(IAsyncEnumerable<T>cursor pagination helpers).RudderLogLevelenum;IRudderLogger.Lognow takes a level.- Package metadata (
Rudder.Core, MIT) and XML documentation.
Changed (breaking)
- Generated models moved to domain folders/namespaces
(
RudderSdk.Core.Models.<Domain>); the flatRudderSdk.Core.DTOnamespace is gone.Battlepass*→BattlePass*,SdkQuest→Quest. BattlepassService→BattlePassService,client.Battlepass→client.BattlePass.client.Scenarios→client.Scenario.ScenarioService.SendAsync→TriggerAsync, now returning the startedPlanRuns.- Scenario events reduced to the canonical set:
OnNotification,OnStoreOffer,OnLeaderboard,OnConfigChanged,OnWait,OnQuest,OnBattlePass,OnBattlePassLevel,OnScenarioCompleted,OnScenarioFailed. Legacy events (OnShowNotification,OnShowStore,OnQuestEvent,OnBattlepassEvent,OnLeaderboardEvent,OnNodeEvent,OnNode,OnCompleted,OnStore,OnRemoteConfigOverride,OnRunCompleted,OnRunFailed) are removed, along with theServices/Scenarios/Legacyfolder. - Session types renamed:
StoreSession→StoreOfferSession(BuyAsync/Buy→PurchaseAsync/Purchase),RemoteConfigOverrideSession→ConfigChangedSession,BattlepassSession→BattlePassSession,BattlepassLevelSession→BattlePassLevelSession,ScenarioRunFailedEvent→ScenarioFailedEvent. StoresService.BuyAsync→PurchaseAsync(storeSlug, offerId, idempotencyKey = null); a null key is replaced with a generated GUID.InventoryService.GetAsyncreturnsIReadOnlyList<PlayerInventoryItem>.StoresService.ListAsyncreturnsIReadOnlyList<Store>.QuestsService.ListAsyncreturnsIReadOnlyList<Quest>.UgcService.GetDownloadUrlAsyncreturns non-nullstringand throwsInvalidOperationExceptionwhen the server returns no URL.BattlePassServicesimple overloads (AddXpAsync(long amount),ClaimRewardAsync(level, track),GetProgressAsync(),PurchasePremiumAsync(idempotencyKey?)); the request-DTO overloads are internal for the scenario runtime.LeaderboardsService.GetRankingAsync/SubmitScoreAsyncare internal; use theFindBySlug(slug)handle (SubmitAsync,ListAsync).AuthService.LoginViaDeviceAsyncremoved; useLoginWithDeviceAsync.ScenarioService.Restore()(sync-over-async) removed; useRestoreAsync.RealtimeService.ConnectAsyncandIRealtimeTransport.ConnectAsynctakeTimeSpantimeouts instead ofint timeoutSeconds.IRudderTransport.SendAsynctakes astring? accessTokeninstead ofRequestOptions;RequestOptionsis removed andEmptyResponseis internal.RudderClientgettersOptions,Transport,TokenStore,DeviceIdProviderare internal.RudderApiException.StatusCodeisint(waslong).IRudderLogger.Log(string)→Log(RudderLogLevel level, string message).- Nullable reference types enabled (
<Nullable>enable</Nullable>). - Remote config cache now includes every config except an explicit
"active": false(a missing flag means active).