2.0.0: slug-based quests, scenarios and offers; environment carried by the token; regenerated models
CI / check (push) Successful in 25s
CI / publish (push) Has been skipped

Claude-Session: https://claude.ai/code/session_01SMCvdwDmuxoaqGgvGBLk1V
This commit is contained in:
edmand46
2026-09-06 22:25:32 +03:00
parent 62025592ba
commit 372ab7cf7e
36 changed files with 138 additions and 90 deletions
+2 -2
View File
@@ -24,11 +24,11 @@ public sealed class BattlePassService
internal BattlePassService(RudderClient client) => _client = client;
/// <summary>Reads current progress: xp, level, premium ownership, claimed tiers.</summary>
public Task<GetBattlePassProgressResponse> GetProgressAsync(string scenarioId, string nodeId, CancellationToken cancellationToken = default)
public Task<GetBattlePassProgressResponse> GetProgressAsync(string scenarioSlug, string nodeId, CancellationToken cancellationToken = default)
=> _client.SendAsync<GetBattlePassProgressRequest, GetBattlePassProgressResponse>(
"POST",
"/sdk/v1/battlepass/progress",
new GetBattlePassProgressRequest { ScenarioId = scenarioId, NodeId = nodeId },
new GetBattlePassProgressRequest { ScenarioSlug = scenarioSlug, NodeId = nodeId },
cancellationToken);
/// <summary>Credits xp and returns the new xp/level and level-up flags.</summary>
+5 -5
View File
@@ -26,7 +26,7 @@ public sealed class BattlePassEffect
public string RunId => _handle.RunId;
/// <summary>Scenario id.</summary>
public string ScenarioId => _handle.ScenarioId;
public string ScenarioSlug => _handle.ScenarioSlug;
/// <summary>Node id.</summary>
public string NodeId => _handle.NodeId;
@@ -39,13 +39,13 @@ public sealed class BattlePassEffect
/// <summary>Reads current progress (xp, level, premium ownership, claimed tiers) for this node.</summary>
public Task<GetBattlePassProgressResponse> GetProgressAsync(CancellationToken cancellationToken = default)
=> _battlePass.GetProgressAsync(_handle.ScenarioId, _handle.NodeId, cancellationToken);
=> _battlePass.GetProgressAsync(_handle.ScenarioSlug, _handle.NodeId, cancellationToken);
/// <summary>Credits xp from a configured source.</summary>
public Task<AddBattlePassXpResponse> AddXpAsync(string source, long amount, CancellationToken cancellationToken = default)
=> _battlePass.AddXpAsync(new AddBattlePassXpRequest
{
ScenarioId = _handle.ScenarioId,
ScenarioSlug = _handle.ScenarioSlug,
NodeId = _handle.NodeId,
RunId = _handle.RunId,
Source = source,
@@ -59,7 +59,7 @@ public sealed class BattlePassEffect
public Task<ClaimBattlePassRewardResponse> ClaimRewardAsync(int level, string track, CancellationToken cancellationToken = default)
=> _battlePass.ClaimRewardAsync(new ClaimBattlePassRewardRequest
{
ScenarioId = _handle.ScenarioId,
ScenarioSlug = _handle.ScenarioSlug,
NodeId = _handle.NodeId,
RunId = _handle.RunId,
Level = level,
@@ -71,7 +71,7 @@ public sealed class BattlePassEffect
{
var response = await _battlePass.PurchasePremiumAsync(new PurchaseBattlePassPremiumRequest
{
ScenarioId = _handle.ScenarioId,
ScenarioSlug = _handle.ScenarioSlug,
NodeId = _handle.NodeId,
RunId = _handle.RunId,
IdempotencyKey = Guid.NewGuid().ToString()
+1 -1
View File
@@ -19,7 +19,7 @@ public sealed class BattlePassLevelEffect
public string RunId => _handle.RunId;
/// <summary>Scenario id.</summary>
public string ScenarioId => _handle.ScenarioId;
public string ScenarioSlug => _handle.ScenarioSlug;
/// <summary>Node id.</summary>
public string NodeId => _handle.NodeId;
+1 -1
View File
@@ -15,7 +15,7 @@ public sealed class LeaderboardEffect
public string RunId => _handle.RunId;
/// <summary>Scenario id.</summary>
public string ScenarioId => _handle.ScenarioId;
public string ScenarioSlug => _handle.ScenarioSlug;
/// <summary>Node id.</summary>
public string NodeId => _handle.NodeId;
+1 -1
View File
@@ -15,7 +15,7 @@ public sealed class NotificationEffect
public string RunId => _handle.RunId;
/// <summary>Scenario id.</summary>
public string ScenarioId => _handle.ScenarioId;
public string ScenarioSlug => _handle.ScenarioSlug;
/// <summary>Node id.</summary>
public string NodeId => _handle.NodeId;
+1 -1
View File
@@ -20,7 +20,7 @@ public sealed class QuestEffect
public string RunId => _handle.RunId;
/// <summary>Scenario id.</summary>
public string ScenarioId => _handle.ScenarioId;
public string ScenarioSlug => _handle.ScenarioSlug;
/// <summary>Node id.</summary>
public string NodeId => _handle.NodeId;
+3 -3
View File
@@ -3,15 +3,15 @@ namespace RudderSdk.Core;
/// <summary>Payload of <see cref="EffectsService.OnScenarioCompleted"/>.</summary>
public sealed class ScenarioCompletedEffect
{
internal ScenarioCompletedEffect(string runId, string scenarioId)
internal ScenarioCompletedEffect(string runId, string scenarioSlug)
{
RunId = runId;
ScenarioId = scenarioId;
ScenarioSlug = scenarioSlug;
}
/// <summary>Server-issued run id.</summary>
public string RunId { get; }
/// <summary>Scenario id.</summary>
public string ScenarioId { get; }
public string ScenarioSlug { get; }
}
+3 -3
View File
@@ -5,10 +5,10 @@ namespace RudderSdk.Core;
/// <summary>Payload of <see cref="EffectsService.OnScenarioFailed"/>.</summary>
public sealed class ScenarioFailedEffect
{
internal ScenarioFailedEffect(string runId, string scenarioId, string nodeId, Exception exception)
internal ScenarioFailedEffect(string runId, string scenarioSlug, string nodeId, Exception exception)
{
RunId = runId;
ScenarioId = scenarioId;
ScenarioSlug = scenarioSlug;
NodeId = nodeId;
Exception = exception;
}
@@ -17,7 +17,7 @@ public sealed class ScenarioFailedEffect
public string RunId { get; }
/// <summary>Scenario id.</summary>
public string ScenarioId { get; }
public string ScenarioSlug { get; }
/// <summary>Node the failure happened at.</summary>
public string NodeId { get; }
+1 -1
View File
@@ -15,7 +15,7 @@ public sealed class StoreOfferEffect
public string RunId => _handle.RunId;
/// <summary>Scenario id.</summary>
public string ScenarioId => _handle.ScenarioId;
public string ScenarioSlug => _handle.ScenarioSlug;
/// <summary>Node id.</summary>
public string NodeId => _handle.NodeId;
+1 -1
View File
@@ -18,7 +18,7 @@ public sealed class WaitEffect
public string RunId => _handle.RunId;
/// <summary>Scenario id.</summary>
public string ScenarioId => _handle.ScenarioId;
public string ScenarioSlug => _handle.ScenarioSlug;
/// <summary>Node id.</summary>
public string NodeId => _handle.NodeId;
+11 -11
View File
@@ -101,7 +101,7 @@ public sealed class EffectsService
var key = (effect.RunId, effect.NodeId);
if (_seen.ContainsKey(key))
continue;
_seen[key] = effect.ScenarioId;
_seen[key] = effect.ScenarioSlug;
if (string.Equals(effect.Type, EffectTypes.Wait, StringComparison.Ordinal))
{
@@ -126,7 +126,7 @@ public sealed class EffectsService
"/sdk/v1/scenarios/callback",
new HandleScenarioCallbackRequest
{
ScenarioId = source.ScenarioId,
ScenarioSlug = source.ScenarioSlug,
NodeId = source.NodeId,
Handle = handle,
RunId = source.RunId
@@ -136,13 +136,13 @@ public sealed class EffectsService
ForgetWait(source.RunId, source.NodeId);
var next = ReadEffect(response?.Effect);
if (next == null)
Emit(OnScenarioCompleted, new ScenarioCompletedEffect(source.RunId, source.ScenarioId));
Emit(OnScenarioCompleted, new ScenarioCompletedEffect(source.RunId, source.ScenarioSlug));
else
Ingest(new[] { next });
}
catch (Exception ex) when (IsDefinitiveRejection(ex))
{
DropRun(source.RunId, source.ScenarioId, source.NodeId, ex);
DropRun(source.RunId, source.ScenarioSlug, source.NodeId, ex);
}
}
@@ -159,7 +159,7 @@ public sealed class EffectsService
"/sdk/v1/scenarios/counter",
new UpdateScenarioCounterRequest
{
ScenarioId = source.ScenarioId,
ScenarioSlug = source.ScenarioSlug,
NodeId = source.NodeId,
CounterKey = counterKey,
Amount = amount,
@@ -173,13 +173,13 @@ public sealed class EffectsService
ForgetWait(source.RunId, source.NodeId);
var next = ReadEffect(response.Effect);
if (next == null)
Emit(OnScenarioCompleted, new ScenarioCompletedEffect(source.RunId, source.ScenarioId));
Emit(OnScenarioCompleted, new ScenarioCompletedEffect(source.RunId, source.ScenarioSlug));
else
Ingest(new[] { next });
}
catch (Exception ex) when (IsDefinitiveRejection(ex))
{
DropRun(source.RunId, source.ScenarioId, source.NodeId, ex);
DropRun(source.RunId, source.ScenarioSlug, source.NodeId, ex);
}
catch (Exception ex)
{
@@ -274,14 +274,14 @@ public sealed class EffectsService
OnScenarioFailed,
new ScenarioFailedEffect(
effect.RunId,
effect.ScenarioId,
effect.ScenarioSlug,
effect.NodeId,
new Exception($"Unsupported scenario node type '{effect.Type}'")));
break;
}
}
private void DropRun(string runId, string scenarioId, string nodeId, Exception exception)
private void DropRun(string runId, string scenarioSlug, string nodeId, Exception exception)
{
lock (_gate)
{
@@ -299,7 +299,7 @@ public sealed class EffectsService
}
}
Emit(OnScenarioFailed, new ScenarioFailedEffect(runId, scenarioId, nodeId, exception));
Emit(OnScenarioFailed, new ScenarioFailedEffect(runId, scenarioSlug, nodeId, exception));
}
private void Reconcile(IEnumerable<PendingEffect>? effects)
@@ -424,7 +424,7 @@ internal sealed class EffectHandle
public string RunId => _effect.RunId;
public string ScenarioId => _effect.ScenarioId;
public string ScenarioSlug => _effect.ScenarioSlug;
public string NodeId => _effect.NodeId;
+1 -1
View File
@@ -9,7 +9,7 @@ namespace RudderSdk.Core;
public static class QuestMetrics
{
/// <summary>Metric for purchasing a store offer; auto-reported on purchase.</summary>
public static string PurchaseOffer(string offerId) => $"purchase.offer:{offerId}";
public static string PurchaseOffer(string offerSlug) => $"purchase.offer:{offerSlug}";
/// <summary>Metric for purchasing a catalog item; auto-reported on purchase.</summary>
public static string PurchaseItem(string itemId) => $"purchase.item:{itemId}";
+3 -3
View File
@@ -27,11 +27,11 @@ public sealed class QuestsService
}
/// <summary>Claims a completed quest's rewards (idempotent server-side).</summary>
public Task<ClaimQuestResponse> ClaimAsync(string questId, CancellationToken cancellationToken = default)
public Task<ClaimQuestResponse> ClaimAsync(string questSlug, CancellationToken cancellationToken = default)
=> _client.SendAsync<ClaimQuestRequest, ClaimQuestResponse>(
"POST",
"/sdk/v1/quests/claim",
new ClaimQuestRequest { QuestId = questId },
new ClaimQuestRequest { QuestSlug = questSlug },
cancellationToken);
/// <summary>Reports progress for a metric and returns the ids of quests completed by this report.</summary>
@@ -43,6 +43,6 @@ public sealed class QuestsService
new ReportQuestProgressRequest { Metric = metric, Amount = amount },
cancellationToken).ConfigureAwait(false);
return response?.CompletedQuestIds ?? new List<string>();
return response?.CompletedQuestSlugs ?? new List<string>();
}
}
+3 -3
View File
@@ -35,17 +35,17 @@ public sealed class StoresService
/// </summary>
public Task<PurchaseOfferResponse> PurchaseAsync(
string storeSlug,
string offerId,
string offerSlug,
string? idempotencyKey = null,
CancellationToken cancellationToken = default)
{
return _client.SendAsync<PurchaseOfferRequest, PurchaseOfferResponse>(
"POST",
"/sdk/v1/stores/" + Url.Encode(storeSlug) + "/offers/" + Url.Encode(offerId) + "/purchase",
"/sdk/v1/stores/" + Url.Encode(storeSlug) + "/offers/" + Url.Encode(offerSlug) + "/purchase",
new PurchaseOfferRequest
{
StoreSlug = storeSlug,
OfferId = offerId,
OfferSlug = offerSlug,
IdempotencyKey = idempotencyKey ?? Guid.NewGuid().ToString()
},
cancellationToken);