Skip to content

Commit 814e843

Browse files
intel352claude
andcommitted
Fix Phase 10 review issues: friends ownership filter and invite appId required
- steam_friends_list: add optional appId input; when set, cross-references IPlayerService/GetOwnedGames/v1/ per friend to return only those who own the specified app (private-profile friends silently omitted on API error) - steam_invite_send: require appId and return error if missing; removes the malformed fallback URL that omitted appId from steam://joinlobby/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent fe6cdca commit 814e843

1 file changed

Lines changed: 58 additions & 6 deletions

File tree

internal/step_steam_presence.go

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"net/url"
7+
"strconv"
78

89
sdk "github.com/GoCodeAlone/workflow/plugin/external/sdk"
910
)
@@ -70,6 +71,7 @@ func (s *steamPresenceSetStep) Execute(_ context.Context, _ map[string]any,
7071
// apiKey string (required)
7172
// steamId string (required)
7273
// relationship string — "friend" (default), "all"
74+
// appId string — optional; when set, only friends who own this app are returned
7375
// baseUrl string — override Steam API base URL (for testing)
7476
//
7577
// Outputs: friends ([]map), count (int)
@@ -97,6 +99,7 @@ func (s *steamFriendsListStep) Execute(_ context.Context, _ map[string]any,
9799
if relationship == "" {
98100
relationship = "friend"
99101
}
102+
appId, _ := merged["appId"].(string)
100103
baseURL, _ := merged["baseUrl"].(string)
101104

102105
client := newSteamClient(baseURL)
@@ -120,12 +123,60 @@ func (s *steamFriendsListStep) Execute(_ context.Context, _ map[string]any,
120123
}
121124
}
122125

126+
// If appId is provided, filter friends to those who own the specified app.
127+
if appId != "" {
128+
friends = filterFriendsByOwnership(client, apiKey, appId, friends)
129+
}
130+
123131
return &sdk.StepResult{Output: map[string]any{
124132
"friends": friends,
125133
"count": len(friends),
126134
}}, nil
127135
}
128136

137+
// filterFriendsByOwnership returns only the friends who own the given appId.
138+
// Calls IPlayerService/GetOwnedGames/v1/ per friend with appids_filter to minimise
139+
// the data returned; friends with a non-empty game list own the app.
140+
func filterFriendsByOwnership(client *steamClient, apiKey, appId string, friends []any) []any {
141+
appIdInt, err := strconv.Atoi(appId)
142+
if err != nil {
143+
// Non-numeric appId — cannot filter, return all.
144+
return friends
145+
}
146+
147+
filtered := make([]any, 0, len(friends))
148+
for _, f := range friends {
149+
fm, ok := f.(map[string]any)
150+
if !ok {
151+
continue
152+
}
153+
fid, _ := fm["steamid"].(string)
154+
if fid == "" {
155+
continue
156+
}
157+
params := url.Values{
158+
"key": {apiKey},
159+
"steamid": {fid},
160+
"appids_filter[0]": {strconv.Itoa(appIdInt)},
161+
"include_appinfo": {"0"},
162+
}
163+
resp, err := client.get("/IPlayerService/GetOwnedGames/v1/", params)
164+
if err != nil {
165+
// On error (e.g. private profile), skip this friend.
166+
continue
167+
}
168+
response, _ := resp["response"].(map[string]any)
169+
if response == nil {
170+
continue
171+
}
172+
games, _ := response["games"].([]any)
173+
if len(games) > 0 {
174+
filtered = append(filtered, f)
175+
}
176+
}
177+
return filtered
178+
}
179+
129180
// step.steam_invite_send — generates a Steam join-game invite for a lobby.
130181
//
131182
// Steam Web API does not expose a server-side invite endpoint; this step
@@ -134,6 +185,7 @@ func (s *steamFriendsListStep) Execute(_ context.Context, _ map[string]any,
134185
//
135186
// Inputs (current or config):
136187
//
188+
// appId string (required) — Steam application ID
137189
// steamId string (required) — inviting player's Steam ID
138190
// lobbyId string (required) — Steam lobby ID to join
139191
// message string — optional custom message
@@ -151,6 +203,10 @@ func (s *steamInviteSendStep) Execute(_ context.Context, _ map[string]any,
151203

152204
merged := mergeConfigs(current, config)
153205

206+
appId, _ := merged["appId"].(string)
207+
if appId == "" {
208+
return nil, fmt.Errorf("step %s: appId is required", s.name)
209+
}
154210
steamId, _ := merged["steamId"].(string)
155211
if steamId == "" {
156212
return nil, fmt.Errorf("step %s: steamId is required", s.name)
@@ -161,12 +217,8 @@ func (s *steamInviteSendStep) Execute(_ context.Context, _ map[string]any,
161217
}
162218
message, _ := merged["message"].(string)
163219

164-
// steam:// invite URL format for joining a Steam lobby.
165-
inviteURL := fmt.Sprintf("steam://joinlobby/%s/%s/%s",
166-
merged["appId"], lobbyId, steamId)
167-
if appId, _ := merged["appId"].(string); appId == "" {
168-
inviteURL = fmt.Sprintf("steam://joinlobby/%s/%s", lobbyId, steamId)
169-
}
220+
// steam:// invite URL format: steam://joinlobby/{appId}/{lobbyId}/{steamId}
221+
inviteURL := fmt.Sprintf("steam://joinlobby/%s/%s/%s", appId, lobbyId, steamId)
170222

171223
return &sdk.StepResult{Output: map[string]any{
172224
"inviteUrl": inviteURL,

0 commit comments

Comments
 (0)