steam_api_client 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -1
- data/docs/USAGE.md +45 -2
- data/lib/steam_api_client/endpoints.rb +34 -0
- data/lib/steam_api_client/models/app_details.rb +5 -3
- data/lib/steam_api_client/models/app_dlc.rb +44 -0
- data/lib/steam_api_client/models/package_details.rb +45 -0
- data/lib/steam_api_client/models/store_search_result.rb +34 -0
- data/lib/steam_api_client/version.rb +1 -1
- data/lib/steam_api_client.rb +3 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '09f9edc74aff7de3fa4975dca173fd7a3388ea4a732671b67db45e09de6a06e5'
|
|
4
|
+
data.tar.gz: 92bbc4d8b4214e32fb2c8d5e8e5a18a3e6844712b4cf916552f02a46a96ec82b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 87a2e53bcd76c574b6f6389071a5156073ad893734ef79377fb34c48406f120652dd93e0a4d8f79b2bd54b5984c6415a5a55e618839ba330d7febb6415c76af8
|
|
7
|
+
data.tar.gz: 3ee3b3c3059e76060a40f63a14bfabd9881983f077f438c8ea90a239d6efeb89602cfed40c7022dfec6225b8b6578508f8821abecae7b4e7287ba0dd261fc60b
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.2.0] - 2026-11-02
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `package_details`, `app_dlc` and `store_search` from the Storefront API: a package's apps and price, an app's DLC, and a search of the store by name. No API key needed (#107).
|
|
14
|
+
|
|
9
15
|
## [1.1.0] - 2026-11-02
|
|
10
16
|
|
|
11
17
|
### Added
|
|
@@ -204,7 +210,8 @@ The versions below were bumped in `version.rb` during development but **never pu
|
|
|
204
210
|
|
|
205
211
|
- Initial gem skeleton.
|
|
206
212
|
|
|
207
|
-
[Unreleased]: https://github.com/jpechaves/steam_api/compare/v1.
|
|
213
|
+
[Unreleased]: https://github.com/jpechaves/steam_api/compare/v1.2.0...HEAD
|
|
214
|
+
[1.2.0]: https://github.com/jpechaves/steam_api/compare/v1.1.0...v1.2.0
|
|
208
215
|
[1.1.0]: https://github.com/jpechaves/steam_api/compare/v1.0.0...v1.1.0
|
|
209
216
|
[1.0.0]: https://github.com/jpechaves/steam_api/compare/v0.10.0...v1.0.0
|
|
210
217
|
[0.11.0]: https://github.com/jpechaves/steam_api/compare/v0.10.0...v0.11.0
|
data/docs/USAGE.md
CHANGED
|
@@ -238,6 +238,49 @@ client.app_details.retrieve(appid: 440).platforms
|
|
|
238
238
|
|
|
239
239
|
`SteamApiClient::AppDetails` fields: `app_id`, `type`, `name`, `required_age`, `is_free`, `dlc`, `detailed_description`, `about_the_game`, `short_description`, `supported_languages`, `header_image`, `website`, `pc_requirements` / `mac_requirements` / `linux_requirements` (`AppDetails::Requirements`: `minimum`, `recommended`, as HTML), `developers`, `publishers`, `price_overview` (`AppDetails::Price`, in cents; `nil` for free apps), `packages`, `package_groups` (`AppDetails::PackageGroup` with `subs`: `AppDetails::Package`), `platforms`, `metacritic` (`score`, `url`), `categories` and `genres` (`id`, `description`), `screenshots`, `movies` (`AppDetails::Movie` with DASH and HLS streams), `recommendations` (the number of user reviews), `achievements` (`total`, `highlighted`), `release_date` (`coming_soon`, `date`), `support_info` (`url`, `email`), `background`, `background_raw`, `content_descriptors` (`ids`, `notes`).
|
|
240
240
|
|
|
241
|
+
#### `package_details`
|
|
242
|
+
|
|
243
|
+
A package (a bundle, or a "sub" such as an edition or a license) in the store, or `nil` when it's unavailable. Storefront API, no key needed. Takes one `packageid:` (Steam rejects several at once), and `country_code:` / `locale:` like `app_details`. Package IDs are in `app_details`' `packages` and `package_groups`.
|
|
244
|
+
|
|
245
|
+
```ruby
|
|
246
|
+
package = client.package_details.retrieve(packageid: 469)
|
|
247
|
+
package.name # => "The Orange Box"
|
|
248
|
+
package.apps # => [#<data SteamApiClient::PackageDetails::App id=220, name="Half-Life 2">, ...]
|
|
249
|
+
package.price # => #<data SteamApiClient::PackageDetails::Price currency="USD", initial=1999, final=1999, discount_percent=0, individual=1998>
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
`SteamApiClient::PackageDetails` fields: `package_id`, `name`, `page_content` (HTML), `purchase_text`, `page_image`, `header_image`, `small_logo`, `apps` (`id`, `name`), `price` (in cents; `individual` is what the apps cost on their own; `nil` for free packages), `platforms` and `release_date` (as in `AppDetails`), `controller` (`full_gamepad`). An invalid ID such as `0` raises `Errors::HttpBadRequest`.
|
|
253
|
+
|
|
254
|
+
#### `app_dlc`
|
|
255
|
+
|
|
256
|
+
An app's DLC, or `nil` when the app is unknown. Storefront API, no key needed. Takes `appid:`, `country_code:` and `locale:`.
|
|
257
|
+
|
|
258
|
+
```ruby
|
|
259
|
+
result = client.app_dlc.retrieve(appid: 292030)
|
|
260
|
+
result.name # => "The Witcher 3: Wild Hunt — Remastered"
|
|
261
|
+
result.dlc.last
|
|
262
|
+
# => #<data SteamApiClient::AppDlc::Dlc id=1229320, name="The Witcher 3: Wild Hunt — Remastered Soundtrack", header_image="https://...",
|
|
263
|
+
# price_overview=#<data SteamApiClient::AppDlc::Price currency="USD", initial=1099, final=1099, discount_percent=0>,
|
|
264
|
+
# platforms=#<data SteamApiClient::AppDetails::Platforms windows=true, mac=true, linux=true>,
|
|
265
|
+
# release_date=#<data SteamApiClient::AppDlc::ReleaseDates steam=1581374766, mac=1581374752, linux=1581374752>, controller_support="full">
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
`price_overview` is `nil` for free DLC and DLC not sold on its own. `release_date` has a unix time per platform (`steam`, `mac`, `linux`), each `nil` when Steam doesn't know it. Steam sometimes adds milliseconds, and the time is then a Float.
|
|
269
|
+
|
|
270
|
+
#### `store_search`
|
|
271
|
+
|
|
272
|
+
Apps in the store matching a search term, at most 10 (Steam's limit, with no paging). Storefront API, no key needed. Takes `term:`, `country_code:` and `locale:`.
|
|
273
|
+
|
|
274
|
+
```ruby
|
|
275
|
+
client.store_search.retrieve(term: "portal").first
|
|
276
|
+
# => #<data SteamApiClient::StoreSearchResult id=620, type="app", name="Portal 2",
|
|
277
|
+
# price=#<data SteamApiClient::StoreSearchResult::Price currency="USD", initial=999, final=999>, tiny_image="https://...",
|
|
278
|
+
# metascore=95, platforms=#<data SteamApiClient::AppDetails::Platforms windows=true, mac=false, linux=true>,
|
|
279
|
+
# streaming_video=false, controller_support="full">
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
`price` is `nil` for free apps, `metascore` when the app has no Metacritic score. No match is `[]`.
|
|
283
|
+
|
|
241
284
|
#### `app_news`
|
|
242
285
|
|
|
243
286
|
The latest news of an app. `count:` is required, `maxlength:` (default 300) shortens each item's contents.
|
|
@@ -346,8 +389,8 @@ Don't retry other 4xx errors: they won't succeed on their own.
|
|
|
346
389
|
|
|
347
390
|
## Limits and caveats
|
|
348
391
|
|
|
349
|
-
- **Rate limits.** Steam's [Web API terms](https://steamcommunity.com/dev/apiterms) allow 100,000 calls per day per key. The Storefront API (`app_details`) is rate limited per IP address, commonly reported at about 200 requests per 5 minutes. Both answer `429` when you go over. Cache what you can.
|
|
350
|
-
- **The Storefront API is unofficial.**
|
|
392
|
+
- **Rate limits.** Steam's [Web API terms](https://steamcommunity.com/dev/apiterms) allow 100,000 calls per day per key. The Storefront API (`app_details`, `package_details`, `app_dlc`, `store_search`) is rate limited per IP address, commonly reported at about 200 requests per 5 minutes. Both answer `429` when you go over. Cache what you can.
|
|
393
|
+
- **The Storefront API is unofficial.** The Storefront endpoints use the API behind Steam's store and Big Picture mode. Valve doesn't document it, and its fields change without notice.
|
|
351
394
|
- **Private profiles.** What a player hides depends on their privacy settings. Depending on the endpoint, Steam answers with an error (`player_achievements`: 403, `player_game_stats`: 400, `player_friends`: 401) or with empty data, which the gem returns as `nil` or `[]` (`player_owned_games`, `player_recent_games`, `player_level`, `player_wishlist`, `player_wishlist_count`, `player_followed_games`). Steam answers the same way for an empty wishlist, so the wishlist endpoints can't tell the two apart. `player_summaries` still returns the public part of the profile.
|
|
352
395
|
- **The key is in the URL.** Steam requires `?key=...` in the query string. Treat logs of request URLs as secrets (see [Configuration](#configuration)), and [rotate your key](https://steamcommunity.com/dev/apikey) if it leaks.
|
|
353
396
|
- **SteamIDs are 64 bit Integers** (e.g. `76561197960435530`). Use `player_steamid` to get one from a vanity URL.
|
|
@@ -26,6 +26,16 @@ module SteamApiClient
|
|
|
26
26
|
}
|
|
27
27
|
),
|
|
28
28
|
|
|
29
|
+
# An app's DLC => AppDlc, or nil when the app is unknown
|
|
30
|
+
Endpoint.new(
|
|
31
|
+
:app_dlc, "dlcforapp/", api: :store, key: false, returns: AppDlc, at: AppDlc.method(:unwrap),
|
|
32
|
+
params: {
|
|
33
|
+
appid: param.integer,
|
|
34
|
+
country_code: param.string(as: :cc, default: "US"),
|
|
35
|
+
locale: param.string(as: :l, default: "en")
|
|
36
|
+
}
|
|
37
|
+
),
|
|
38
|
+
|
|
29
39
|
# Global achievement unlock percentages of an app => [GlobalAchievement]
|
|
30
40
|
# @see https://developer.valvesoftware.com/wiki/Steam_Web_API#GetGlobalAchievementPercentagesForApp_.28v0002.29
|
|
31
41
|
Endpoint.new(
|
|
@@ -55,6 +65,19 @@ module SteamApiClient
|
|
|
55
65
|
params: {appid: param.integer}
|
|
56
66
|
),
|
|
57
67
|
|
|
68
|
+
# Details of a package (a bundle or a sub) in the store => PackageDetails, or nil when unavailable
|
|
69
|
+
# @see https://wiki.teamfortress.com/wiki/User:RJackson/StorefrontAPI#packagedetails
|
|
70
|
+
Endpoint.new(
|
|
71
|
+
:package_details, "packagedetails/", api: :store, key: false, returns: PackageDetails,
|
|
72
|
+
at: PackageDetails.method(:unwrap),
|
|
73
|
+
params: {
|
|
74
|
+
# Steam rejects several IDs at once
|
|
75
|
+
packageid: param.integer(as: :packageids),
|
|
76
|
+
country_code: param.string(as: :cc, default: "US"),
|
|
77
|
+
locale: param.string(as: :l, default: "en")
|
|
78
|
+
}
|
|
79
|
+
),
|
|
80
|
+
|
|
58
81
|
# A player's achievements in an app => PlayerAchievements
|
|
59
82
|
# @see https://developer.valvesoftware.com/wiki/Steam_Web_API#GetPlayerAchievements_.28v0001.29
|
|
60
83
|
Endpoint.new(
|
|
@@ -137,6 +160,17 @@ module SteamApiClient
|
|
|
137
160
|
Endpoint.new(
|
|
138
161
|
:player_wishlist_count, "IWishlistService/GetWishlistItemCount/v1/", key: false, returns: :integer, at: %i[response count],
|
|
139
162
|
params: {steamid: param.integer}
|
|
163
|
+
),
|
|
164
|
+
|
|
165
|
+
# Apps in the store matching a search term => [StoreSearchResult] (at most 10)
|
|
166
|
+
Endpoint.new(
|
|
167
|
+
:store_search, "storesearch/", api: :store, key: false, returns: [StoreSearchResult],
|
|
168
|
+
at: StoreSearchResult.method(:unwrap),
|
|
169
|
+
params: {
|
|
170
|
+
term: param.string,
|
|
171
|
+
country_code: param.string(as: :cc, default: "US"),
|
|
172
|
+
locale: param.string(as: :l, default: "en")
|
|
173
|
+
}
|
|
140
174
|
)
|
|
141
175
|
].to_h { |endpoint| [endpoint.name, endpoint] }.freeze
|
|
142
176
|
end
|
|
@@ -105,13 +105,15 @@ module SteamApiClient
|
|
|
105
105
|
) do
|
|
106
106
|
# Steam keys the response by app ID: {"570": {"success": true, "data": {...}}}.
|
|
107
107
|
# Returns the data, or nil when the app is unavailable (success: false).
|
|
108
|
+
# The Storefront's other details endpoints (packagedetails) answer the same way.
|
|
108
109
|
# @param [Hash] json
|
|
110
|
+
# @param [Symbol] id_key the key the ID is added under
|
|
109
111
|
# @return [Hash, nil]
|
|
110
|
-
def self.unwrap(json)
|
|
111
|
-
|
|
112
|
+
def self.unwrap(json, id_key: :steam_appid)
|
|
113
|
+
id, entry = json.first
|
|
112
114
|
return unless entry.is_a?(Hash) && entry[:success]
|
|
113
115
|
|
|
114
|
-
{
|
|
116
|
+
{id_key => id.to_s}.merge(entry.fetch(:data, {}))
|
|
115
117
|
end
|
|
116
118
|
end
|
|
117
119
|
parts.each { |name, model| AppDetails.const_set(name, model) }
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module SteamApiClient
|
|
2
|
+
# The parts of AppDlc, built first, then named under it below (e.g. AppDlc::Dlc)
|
|
3
|
+
parts = {
|
|
4
|
+
Price: Model.define(
|
|
5
|
+
currency: :string,
|
|
6
|
+
# In cents
|
|
7
|
+
initial: :integer,
|
|
8
|
+
final: :integer,
|
|
9
|
+
discount_percent: :integer
|
|
10
|
+
),
|
|
11
|
+
# Unix times, per platform. Steam sometimes adds milliseconds, which makes them Floats.
|
|
12
|
+
ReleaseDates: Model.define(
|
|
13
|
+
steam: [:number, optional: true],
|
|
14
|
+
mac: [:number, optional: true],
|
|
15
|
+
linux: [:number, optional: true]
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
parts[:Dlc] = Model.define(
|
|
19
|
+
id: :integer,
|
|
20
|
+
name: :string,
|
|
21
|
+
header_image: [:string, optional: true],
|
|
22
|
+
# Not sent for free DLC, or DLC not sold on its own
|
|
23
|
+
price_overview: [parts[:Price], optional: true],
|
|
24
|
+
platforms: [AppDetails::Platforms, optional: true],
|
|
25
|
+
release_date: [parts[:ReleaseDates], optional: true],
|
|
26
|
+
# "full", "partial", or nil
|
|
27
|
+
controller_support: [:string, optional: true]
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# An app's DLC, from `app_dlc`
|
|
31
|
+
AppDlc = Model.define(
|
|
32
|
+
app_id: [:integer, from: :appid],
|
|
33
|
+
name: :string,
|
|
34
|
+
dlc: [[parts[:Dlc]], default: []]
|
|
35
|
+
) do
|
|
36
|
+
# Steam answers {"status": 2} for an unknown app
|
|
37
|
+
# @param [Hash] json
|
|
38
|
+
# @return [Hash, nil] the JSON, or nil when the app is unknown
|
|
39
|
+
def self.unwrap(json)
|
|
40
|
+
json if json[:status] == 1
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
parts.each { |name, model| AppDlc.const_set(name, model) }
|
|
44
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module SteamApiClient
|
|
2
|
+
# The parts of PackageDetails, built first, then named under it below
|
|
3
|
+
# (e.g. PackageDetails::App)
|
|
4
|
+
parts = {
|
|
5
|
+
App: Model.define(id: :integer, name: :string),
|
|
6
|
+
Price: Model.define(
|
|
7
|
+
currency: :string,
|
|
8
|
+
# In cents
|
|
9
|
+
initial: :integer,
|
|
10
|
+
final: :integer,
|
|
11
|
+
discount_percent: :integer,
|
|
12
|
+
# The sum of the apps' own prices, in cents (0 when they aren't sold separately)
|
|
13
|
+
individual: [:integer, optional: true]
|
|
14
|
+
),
|
|
15
|
+
Controller: Model.define(full_gamepad: :boolean)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# A package (a bundle or a sub) in the store, from `package_details`. Every
|
|
19
|
+
# field is nil when Steam leaves it out.
|
|
20
|
+
# @see https://wiki.teamfortress.com/wiki/User:RJackson/StorefrontAPI#packagedetails
|
|
21
|
+
PackageDetails = Model.define(
|
|
22
|
+
package_id: [:integer, from: :packageid],
|
|
23
|
+
name: [:string, optional: true],
|
|
24
|
+
# HTML
|
|
25
|
+
page_content: [:string, optional: true],
|
|
26
|
+
purchase_text: [:string, optional: true],
|
|
27
|
+
page_image: [:string, optional: true],
|
|
28
|
+
header_image: [:string, optional: true],
|
|
29
|
+
small_logo: [:string, optional: true],
|
|
30
|
+
apps: [[parts[:App]], default: []],
|
|
31
|
+
# Not sent for free packages
|
|
32
|
+
price: [parts[:Price], optional: true],
|
|
33
|
+
platforms: [AppDetails::Platforms, optional: true],
|
|
34
|
+
controller: [parts[:Controller], optional: true],
|
|
35
|
+
release_date: [AppDetails::ReleaseDate, optional: true]
|
|
36
|
+
) do
|
|
37
|
+
# The package's data, or nil when it's unavailable (see AppDetails.unwrap)
|
|
38
|
+
# @param [Hash] json
|
|
39
|
+
# @return [Hash, nil]
|
|
40
|
+
def self.unwrap(json)
|
|
41
|
+
AppDetails.unwrap(json, id_key: :packageid)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
parts.each { |name, model| PackageDetails.const_set(name, model) }
|
|
45
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module SteamApiClient
|
|
2
|
+
# Built first, then named StoreSearchResult::Price below
|
|
3
|
+
price = Model.define(
|
|
4
|
+
currency: :string,
|
|
5
|
+
# In cents
|
|
6
|
+
initial: :integer,
|
|
7
|
+
final: :integer
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
# One result of a store search, from `store_search`
|
|
11
|
+
StoreSearchResult = Model.define(
|
|
12
|
+
id: :integer,
|
|
13
|
+
# "app"
|
|
14
|
+
type: :string,
|
|
15
|
+
name: :string,
|
|
16
|
+
# Not sent for free apps
|
|
17
|
+
price: [price, optional: true],
|
|
18
|
+
tiny_image: [:string, optional: true],
|
|
19
|
+
# nil when the app has no Metacritic score
|
|
20
|
+
metascore: [:integer, optional: true],
|
|
21
|
+
platforms: [AppDetails::Platforms, optional: true],
|
|
22
|
+
streaming_video: [:boolean, from: :streamingvideo, optional: true],
|
|
23
|
+
# "full", "partial", or nil
|
|
24
|
+
controller_support: [:string, optional: true]
|
|
25
|
+
) do
|
|
26
|
+
# The results. Steam sends "" as the metascore of apps without one.
|
|
27
|
+
# @param [Hash] json
|
|
28
|
+
# @return [Array<Hash>, nil]
|
|
29
|
+
def self.unwrap(json)
|
|
30
|
+
json[:items]&.map { |item| (item[:metascore] == "") ? item.merge(metascore: nil) : item }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
StoreSearchResult.const_set(:Price, price)
|
|
34
|
+
end
|
data/lib/steam_api_client.rb
CHANGED
|
@@ -30,6 +30,9 @@ require_relative "steam_api_client/models/player_game_stats"
|
|
|
30
30
|
require_relative "steam_api_client/models/news_item"
|
|
31
31
|
require_relative "steam_api_client/models/global_achievement"
|
|
32
32
|
require_relative "steam_api_client/models/app_details"
|
|
33
|
+
require_relative "steam_api_client/models/package_details"
|
|
34
|
+
require_relative "steam_api_client/models/app_dlc"
|
|
35
|
+
require_relative "steam_api_client/models/store_search_result"
|
|
33
36
|
require_relative "steam_api_client/models/wishlist_item"
|
|
34
37
|
|
|
35
38
|
require_relative "steam_api_client/endpoints"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: steam_api_client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- João Pedro
|
|
@@ -54,13 +54,16 @@ files:
|
|
|
54
54
|
- lib/steam_api_client/model/field.rb
|
|
55
55
|
- lib/steam_api_client/model/scalars.rb
|
|
56
56
|
- lib/steam_api_client/models/app_details.rb
|
|
57
|
+
- lib/steam_api_client/models/app_dlc.rb
|
|
57
58
|
- lib/steam_api_client/models/friend.rb
|
|
58
59
|
- lib/steam_api_client/models/game.rb
|
|
59
60
|
- lib/steam_api_client/models/global_achievement.rb
|
|
60
61
|
- lib/steam_api_client/models/news_item.rb
|
|
62
|
+
- lib/steam_api_client/models/package_details.rb
|
|
61
63
|
- lib/steam_api_client/models/player_achievements.rb
|
|
62
64
|
- lib/steam_api_client/models/player_game_stats.rb
|
|
63
65
|
- lib/steam_api_client/models/player_summary.rb
|
|
66
|
+
- lib/steam_api_client/models/store_search_result.rb
|
|
64
67
|
- lib/steam_api_client/models/wishlist_item.rb
|
|
65
68
|
- lib/steam_api_client/request.rb
|
|
66
69
|
- lib/steam_api_client/requestor.rb
|