From a217f255b8f142f366c3994ca7165d9e64909c26 Mon Sep 17 00:00:00 2001 From: edmand46 Date: Sun, 6 Sep 2026 22:25:32 +0300 Subject: [PATCH] v2.0.0: module path /v2, quest slugs, per-environment admin keys, regenerated models Claude-Session: https://claude.ai/code/session_01SMCvdwDmuxoaqGgvGBLk1V --- CHANGELOG.md | 32 +++++++++++++++++++++++ README.md | 27 ++++++++++--------- go.mod | 2 +- inventory.go | 2 +- leaderboard.go | 2 +- leaderboards.go | 2 +- models/adminplayerquest.go | 2 +- models/batchplayerquestsitem.go | 4 +-- models/environmentname.go | 10 +++++++ models/questdefinition.go | 1 + models/verifyplayerauthresponse.go | 7 ++--- player_quests.go | 10 +++---- player_storage.go | 2 +- players.go | 2 +- quests.go | 2 +- skills/rudder-go-sdk/SKILL.md | 19 ++++++++------ skills/rudder-go-sdk/reference/players.md | 4 ++- skills/rudder-go-sdk/reference/quests.md | 8 +++--- storage.go | 2 +- types.go | 2 +- wallet.go | 2 +- 21 files changed, 98 insertions(+), 46 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 models/environmentname.go diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..aece17b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,32 @@ +# Changelog + +## 2.0.0 + +Breaking change — major bump, required by the backend environments release. +The module path gains the Go major-version suffix: import +`hub.rudder.build/rudder/rudder-go-sdk/v2` and pull it with +`go get hub.rudder.build/rudder/rudder-go-sdk/v2@latest`. Nothing else about +the import changes: the package is still `rudder`. + +Admin keys are now per environment. A project has exactly two environments, +`staging` and `prod`, and each has its own Admin Key, so the key you configure +decides which environment every call reads and writes. There is no environment +option on the client or on any method, and there is nothing to migrate in code +— but the key itself changed: the old project Admin Key became the `prod` key +and a separate `staging` key was generated, both visible under project +Settings. Players are per environment too, so a player id from one environment +does not resolve in the other, and the same holds for wallets, inventory, +storage, counters, quests, runs, battle pass, purchases and leaderboard +entries. + +Quests are addressed by slug, because ids differ between staging and prod +while slugs are stable. `PlayerQuestParameters.QuestID` is now +`PlayerQuestParameters.QuestSlug`, `PlayerQuestRef` carries `QuestSlug` +instead of `QuestID`, `PlayerQuest` reports `QuestSlug`, and `Quest` +(the catalog definition) gained `Slug` alongside its `ID`. +`Players.VerifyAuth` additionally returns `Environment`, which always matches +the admin key's environment. + +Environment create, delete and merge, and project-level admin key +regeneration, were removed from the platform. This SDK never exposed them, so +nothing is gone from its surface. diff --git a/README.md b/README.md index 26ca9e6..979a8fa 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ```bash go env -w GOPRIVATE=hub.rudder.build/* -go get hub.rudder.build/rudder/rudder-go-sdk@latest +go get hub.rudder.build/rudder/rudder-go-sdk/v2@latest ``` Требуется Go 1.21+. Токен не нужен — репозиторий публичный. @@ -18,15 +18,18 @@ go get hub.rudder.build/rudder/rudder-go-sdk@latest ## Версионирование Потребители фиксируют версию по git-тегу -(`go get hub.rudder.build/rudder/rudder-go-sdk@vX.Y.Z`). Первый тег `v0.1.0` -будет создан при релизе; до него версионирования нет. +(`go get hub.rudder.build/rudder/rudder-go-sdk/v2@vX.Y.Z`). Текущая мажорная +версия — `v2`, поэтому путь модуля содержит суффикс `/v2`, а импорты идут +через `hub.rudder.build/rudder/rudder-go-sdk/v2`. ## Доступ -`AdminKey` — это per-project Admin Key: поле «Admin Key» в настройках проекта -в дашборде (app.rudder.build → проект → Settings). Ключ сам определяет -проект, отдельный project ID не нужен. Храните его только на сервере — -никогда не вшивайте в игровые клиенты. +`AdminKey` — это Admin Key окружения: у проекта их два, для `staging` и для +`prod` (app.rudder.build → проект → Settings → Environments). Ключ сам +определяет и проект, и окружение, поэтому ни project ID, ни параметр +окружения передавать не нужно; игроки и контент разных окружений полностью +изолированы. Храните ключ только на сервере — никогда не вшивайте в игровые +клиенты. ## Usage @@ -76,7 +79,7 @@ updated, err := player.Storage().Upsert(ctx, rudder.UpsertPlayerStorageParameter err = player.Storage().Delete(ctx, rudder.DeletePlayerStorageParameters{Type: "settings"}) quests, err := player.Quests().List(ctx) -err = player.Quests().Reset(ctx, rudder.PlayerQuestParameters{QuestID: "daily-1"}) +err = player.Quests().Reset(ctx, rudder.PlayerQuestParameters{QuestSlug: "daily-1"}) // ForceComplete и ForceClaim — аналогично updatedPlayer, err := player.Update(ctx, rudder.UpdatePlayerParameters{Nickname: "Neo"}) @@ -145,12 +148,12 @@ err = client.Players.Delete(ctx, rudder.DeletePlayersParameters{ ## Верификация авторизации `Players.VerifyAuth` — одиночный (не batch) вызов `POST /players/auth/verify`: -проверяет access token игрока и возвращает `playerId`, `projectId` и `status` -(`active`/`banned`/`deleted`). +проверяет access token игрока и возвращает `playerId`, `projectId`, +`environment` (`staging`/`prod`) и `status` (`active`/`banned`/`deleted`). ```go verification, err := client.Players.VerifyAuth(ctx, accessToken) -// verification.PlayerID, verification.ProjectID, verification.Status +// verification.PlayerID, verification.ProjectID, verification.Environment, verification.Status ``` `VerifyWebhookSignature` — пакетный хелпер для приёма webhook'ов с подписью @@ -164,7 +167,7 @@ if !rudder.VerifyWebhookSignature(secret, body, r.Header.Get("X-Signature")) { err = client.Quests.Reset(ctx, rudder.PlayerQuestsParameters{ Items: []rudder.PlayerQuestRef{ - {PlayerID: "p1", QuestID: "daily-1"}, + {PlayerID: "p1", QuestSlug: "daily-1"}, }, }) // ForceComplete и ForceClaim — аналогично diff --git a/go.mod b/go.mod index f988277..1691b8b 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module hub.rudder.build/rudder/rudder-go-sdk +module hub.rudder.build/rudder/rudder-go-sdk/v2 go 1.21 diff --git a/inventory.go b/inventory.go index 50e926a..2a02cd2 100644 --- a/inventory.go +++ b/inventory.go @@ -6,7 +6,7 @@ import ( "net/url" "strconv" - "hub.rudder.build/rudder/rudder-go-sdk/models" + "hub.rudder.build/rudder/rudder-go-sdk/v2/models" ) type InventoryService struct { diff --git a/leaderboard.go b/leaderboard.go index c363419..ccf9ec9 100644 --- a/leaderboard.go +++ b/leaderboard.go @@ -6,7 +6,7 @@ import ( "net/url" "strconv" - "hub.rudder.build/rudder/rudder-go-sdk/models" + "hub.rudder.build/rudder/rudder-go-sdk/v2/models" ) type LeaderboardHandle struct { diff --git a/leaderboards.go b/leaderboards.go index 0b2b6b3..1eb72b1 100644 --- a/leaderboards.go +++ b/leaderboards.go @@ -6,7 +6,7 @@ import ( "net/url" "strconv" - "hub.rudder.build/rudder/rudder-go-sdk/models" + "hub.rudder.build/rudder/rudder-go-sdk/v2/models" ) type LeaderboardsService struct { diff --git a/models/adminplayerquest.go b/models/adminplayerquest.go index 289ad71..f44786f 100644 --- a/models/adminplayerquest.go +++ b/models/adminplayerquest.go @@ -5,6 +5,6 @@ package models type AdminPlayerQuest struct { Name string `json:"name,omitempty"` Objectives []AdminPlayerQuestObjective `json:"objectives,omitempty"` - QuestID string `json:"questId,omitempty"` + QuestSlug string `json:"questSlug,omitempty"` Status string `json:"status,omitempty"` } diff --git a/models/batchplayerquestsitem.go b/models/batchplayerquestsitem.go index 3a480ae..c7b8354 100644 --- a/models/batchplayerquestsitem.go +++ b/models/batchplayerquestsitem.go @@ -3,6 +3,6 @@ package models type BatchPlayerQuestsItem struct { - PlayerID string `json:"playerId,omitempty"` - QuestID string `json:"questId,omitempty"` + PlayerID string `json:"playerId,omitempty"` + QuestSlug string `json:"questSlug,omitempty"` } diff --git a/models/environmentname.go b/models/environmentname.go new file mode 100644 index 0000000..164ada6 --- /dev/null +++ b/models/environmentname.go @@ -0,0 +1,10 @@ +// Code generated by apigen. DO NOT EDIT. + +package models + +type EnvironmentName string + +const ( + EnvironmentNameStaging EnvironmentName = "staging" + EnvironmentNameProd EnvironmentName = "prod" +) diff --git a/models/questdefinition.go b/models/questdefinition.go index 894db39..57f9c7a 100644 --- a/models/questdefinition.go +++ b/models/questdefinition.go @@ -8,5 +8,6 @@ type QuestDefinition struct { NextQuestID string `json:"nextQuestId,omitempty"` Objectives []QuestObjective `json:"objectives,omitempty"` Rewards []QuestRewardDefinition `json:"rewards,omitempty"` + Slug string `json:"slug,omitempty"` Status string `json:"status,omitempty"` } diff --git a/models/verifyplayerauthresponse.go b/models/verifyplayerauthresponse.go index 3c3ba64..91f2c84 100644 --- a/models/verifyplayerauthresponse.go +++ b/models/verifyplayerauthresponse.go @@ -3,7 +3,8 @@ package models type VerifyPlayerAuthResponse struct { - PlayerID string `json:"playerId,omitempty"` - ProjectID string `json:"projectId,omitempty"` - Status string `json:"status,omitempty"` + Environment EnvironmentName `json:"environment,omitempty"` + PlayerID string `json:"playerId,omitempty"` + ProjectID string `json:"projectId,omitempty"` + Status string `json:"status,omitempty"` } diff --git a/player_quests.go b/player_quests.go index b1dd63b..920b32f 100644 --- a/player_quests.go +++ b/player_quests.go @@ -5,7 +5,7 @@ import ( "net/http" "net/url" - "hub.rudder.build/rudder/rudder-go-sdk/models" + "hub.rudder.build/rudder/rudder-go-sdk/v2/models" ) type PlayerQuestsHandle struct { @@ -24,26 +24,26 @@ func (h *PlayerQuestsHandle) List(ctx context.Context) ([]PlayerQuest, error) { type PlayerQuestParameters struct { IdempotencyKey string - QuestID string + QuestSlug string } func (h *PlayerQuestsHandle) Reset(ctx context.Context, parameters PlayerQuestParameters) error { return h.quests.Reset(ctx, PlayerQuestsParameters{ IdempotencyKey: parameters.IdempotencyKey, - Items: []PlayerQuestRef{{PlayerID: h.playerID, QuestID: parameters.QuestID}}, + Items: []PlayerQuestRef{{PlayerID: h.playerID, QuestSlug: parameters.QuestSlug}}, }) } func (h *PlayerQuestsHandle) ForceComplete(ctx context.Context, parameters PlayerQuestParameters) error { return h.quests.ForceComplete(ctx, PlayerQuestsParameters{ IdempotencyKey: parameters.IdempotencyKey, - Items: []PlayerQuestRef{{PlayerID: h.playerID, QuestID: parameters.QuestID}}, + Items: []PlayerQuestRef{{PlayerID: h.playerID, QuestSlug: parameters.QuestSlug}}, }) } func (h *PlayerQuestsHandle) ForceClaim(ctx context.Context, parameters PlayerQuestParameters) error { return h.quests.ForceClaim(ctx, PlayerQuestsParameters{ IdempotencyKey: parameters.IdempotencyKey, - Items: []PlayerQuestRef{{PlayerID: h.playerID, QuestID: parameters.QuestID}}, + Items: []PlayerQuestRef{{PlayerID: h.playerID, QuestSlug: parameters.QuestSlug}}, }) } diff --git a/player_storage.go b/player_storage.go index edaedd2..9868d0b 100644 --- a/player_storage.go +++ b/player_storage.go @@ -5,7 +5,7 @@ import ( "net/http" "net/url" - "hub.rudder.build/rudder/rudder-go-sdk/models" + "hub.rudder.build/rudder/rudder-go-sdk/v2/models" ) type PlayerStorageHandle struct { diff --git a/players.go b/players.go index d11cd60..9e0dee8 100644 --- a/players.go +++ b/players.go @@ -6,7 +6,7 @@ import ( "net/url" "strconv" - "hub.rudder.build/rudder/rudder-go-sdk/models" + "hub.rudder.build/rudder/rudder-go-sdk/v2/models" ) type PlayersService struct { diff --git a/quests.go b/quests.go index f494c1b..cb5ec71 100644 --- a/quests.go +++ b/quests.go @@ -6,7 +6,7 @@ import ( "net/url" "strconv" - "hub.rudder.build/rudder/rudder-go-sdk/models" + "hub.rudder.build/rudder/rudder-go-sdk/v2/models" ) type QuestsService struct { diff --git a/skills/rudder-go-sdk/SKILL.md b/skills/rudder-go-sdk/SKILL.md index 26edfba..8bcfdec 100644 --- a/skills/rudder-go-sdk/SKILL.md +++ b/skills/rudder-go-sdk/SKILL.md @@ -1,13 +1,13 @@ --- name: rudder-go-sdk -description: Use when working with the Rudder Go server SDK (package rudder, module hub.rudder.build/rudder/rudder-go-sdk) for server-side admin operations — players, wallet, inventory, storage, quests, leaderboards, webhook signature verification. +description: Use when working with the Rudder Go server SDK (package rudder, module hub.rudder.build/rudder/rudder-go-sdk/v2) for server-side admin operations — players, wallet, inventory, storage, quests, leaderboards, webhook signature verification. --- # Rudder Go server SDK Server-side admin SDK for the Rudder LiveOps platform. Covers the `/game/v1` admin surface, authenticated with `X-API-Key`. Module: -`hub.rudder.build/rudder/rudder-go-sdk`, package `rudder`. Requires Go 1.21+. +`hub.rudder.build/rudder/rudder-go-sdk/v2`, package `rudder`. Requires Go 1.21+. ## Install @@ -15,17 +15,20 @@ The module is served from a self-hosted Gitea, bypassing proxy.golang.org: ```bash go env -w GOPRIVATE=hub.rudder.build/* -go get hub.rudder.build/rudder/rudder-go-sdk@latest +go get hub.rudder.build/rudder/rudder-go-sdk/v2@latest ``` ## Client init -`AdminKey` is the per-project Admin Key from the dashboard -(app.rudder.build → project → Settings). The key identifies the project; no -separate project ID is needed. Keep it server-side only, never in game clients. +`AdminKey` is the Admin Key of one environment. A project has exactly two, +`staging` and `prod` (app.rudder.build → project → Settings → Environments). +The key identifies both the project and the environment, so no project ID and +no environment argument are ever passed; players, wallets, inventory, storage, +quests and leaderboard entries of the two environments are fully isolated. +Keep it server-side only, never in game clients. ```go -import rudder "hub.rudder.build/rudder/rudder-go-sdk" +import rudder "hub.rudder.build/rudder/rudder-go-sdk/v2" client, err := rudder.New(rudder.Config{ AdminKey: os.Getenv("RUDDER_ADMIN_KEY"), @@ -40,7 +43,7 @@ client, err := rudder.New(rudder.Config{ Public types live in package `rudder` (aliases in `types.go`). The `models` package is generated wire format — never import it in application code and never edit it by hand (regenerate via `make generate-openapi` in -liveops-gateway). +liveops-backend). ## Batch-first mutation model diff --git a/skills/rudder-go-sdk/reference/players.md b/skills/rudder-go-sdk/reference/players.md index 98512c6..1e85823 100644 --- a/skills/rudder-go-sdk/reference/players.md +++ b/skills/rudder-go-sdk/reference/players.md @@ -19,7 +19,9 @@ func (s *PlayersService) Get(ctx context.Context, playerID string) (*PlayerDetai func (s *PlayersService) VerifyAuth(ctx context.Context, accessToken string) (*PlayerAuthVerification, error) // Single (non-batch) call: POST /players/auth/verify. -// PlayerAuthVerification: {PlayerID, ProjectID, Status} — Status is "active"/"banned"/"deleted". +// PlayerAuthVerification: {PlayerID, ProjectID, Environment, Status} — Status is "active"/"banned"/"deleted". +// Environment ("staging"/"prod") is the environment the token was issued for; it always +// matches the admin key, since both come from the same environment. ``` ## Batch mutations diff --git a/skills/rudder-go-sdk/reference/quests.md b/skills/rudder-go-sdk/reference/quests.md index d7ee34c..f206eaf 100644 --- a/skills/rudder-go-sdk/reference/quests.md +++ b/skills/rudder-go-sdk/reference/quests.md @@ -12,7 +12,7 @@ type ListQuestsParameters struct { Cursor *string } // QuestList: {Items []Quest, NextCursor string} -// Quest: {ID, Name, Status, NextQuestID, Objectives []QuestObjective, Rewards []QuestReward} +// Quest: {ID, Slug, Name, Status, NextQuestID, Objectives []QuestObjective, Rewards []QuestReward} // QuestObjective: {ID, Metric, Target int64} // QuestReward: {Amount int64, Currency, ItemID} ``` @@ -28,7 +28,7 @@ func (s *QuestsService) ForceClaim(ctx context.Context, parameters PlayerQuestsP type PlayerQuestsParameters struct { IdempotencyKey string - Items []PlayerQuestRef // {PlayerID, QuestID} + Items []PlayerQuestRef // {PlayerID, QuestSlug} } ``` @@ -38,7 +38,7 @@ type PlayerQuestsParameters struct { ```go func (h *PlayerQuestsHandle) List(ctx context.Context) ([]PlayerQuest, error) -// PlayerQuest: {QuestID, Name, Status, Objectives []PlayerQuestObjective} +// PlayerQuest: {QuestSlug, Name, Status, Objectives []PlayerQuestObjective} // PlayerQuestObjective: {ObjectiveID, Current int64, Target int64} func (h *PlayerQuestsHandle) Reset(ctx context.Context, parameters PlayerQuestParameters) error @@ -47,6 +47,6 @@ func (h *PlayerQuestsHandle) ForceClaim(ctx context.Context, parameters PlayerQu type PlayerQuestParameters struct { IdempotencyKey string - QuestID string + QuestSlug string } ``` diff --git a/storage.go b/storage.go index 88aa56b..ed7e731 100644 --- a/storage.go +++ b/storage.go @@ -6,7 +6,7 @@ import ( "net/url" "strconv" - "hub.rudder.build/rudder/rudder-go-sdk/models" + "hub.rudder.build/rudder/rudder-go-sdk/v2/models" ) type StorageService struct { diff --git a/types.go b/types.go index af5ba46..661f01d 100644 --- a/types.go +++ b/types.go @@ -1,6 +1,6 @@ package rudder -import "hub.rudder.build/rudder/rudder-go-sdk/models" +import "hub.rudder.build/rudder/rudder-go-sdk/v2/models" // Domain types are aliases of generated OpenAPI models so callers import // only this package. models/ is wire format and is not part of the public API. diff --git a/wallet.go b/wallet.go index 1f9c814..c16a1f0 100644 --- a/wallet.go +++ b/wallet.go @@ -6,7 +6,7 @@ import ( "net/url" "strconv" - "hub.rudder.build/rudder/rudder-go-sdk/models" + "hub.rudder.build/rudder/rudder-go-sdk/v2/models" ) type WalletService struct {