steam-user 0.1.0

Steam User web client for Rust - HTTP-based Steam Community interactions
Documentation
//! Shared trait defining the `SteamUser` API surface.
//!
//! Both `SteamUser` (local), `RemoteSteamUser` (HTTP client), and
//! `GasSteamUser` (GAS proxy) implement [`SteamUserApi`], giving compile-time
//! guarantees that every public method exists in all implementations.
//!
//! Methods return strongly-typed results matching the types in
//! [`crate::types`].

use std::collections::HashMap;

use async_trait::async_trait;
use steamid::SteamID;

use crate::types::{
    AccountDetails, ActiveInventory, ActivityCommentResponse, AddPhoneNumberResponse, AliasEntry, Amount, AppDetail, AppId, AppListItem, AssetId, AvatarHistoryEntry, AvatarUploadResponse, BoosterPackEntry, BoosterResult, CommunitySearchResult, ConfirmPhoneCodeResponse, Confirmation, ContextId, CsgoAccountStats, DynamicStoreUserData, EconItem, FriendActivity, FriendActivityResponse, FriendDetails, FriendListPage, GemResult, GemValue, GroupInfoXml, GroupOverview, HelpRequest, InventoryHistoryItem, InventoryHistoryResult, InvitableGroup, ItemNameId, ItemOrdersHistogramResponse, LoggedInResult, MarketHistoryResponse, MarketRestrictions,
    MatchHistoryResponse, MyListingsResult, Notifications, OwnedApp, OwnedAppDetail, PendingFriendList, PlayerReport, PriceCents, PriceOverview, PrivacySettings, PurchaseHistoryItem, RedeemWalletCodeResponse, RemovePhoneResult, SellItemResult, SimpleSteamAppList, SteamAppVersionInfo, SteamGuardStatus, SteamProfile, SteamUserProfile, TradeOfferAsset, TradeOfferResult, TradeOffersResponse, TwoFactorResponse, UserComment, UserSummaryProfile, UserSummaryXml, WalletBalance,
};

/// Unified API surface for Steam user operations.
///
/// Implementing this trait for a type guarantees it exposes every
/// method in the canonical `steam-user` crate.  If a method is added
/// to the trait, any implementor that is missing it will fail to compile.
#[async_trait]
pub trait SteamUserApi {
    /// The error type returned by all methods.
    type Error;

    // =====================================================================
    // Account
    // =====================================================================

    async fn get_account_details(&self) -> Result<AccountDetails, Self::Error>;
    async fn get_steam_wallet_balance(&self) -> Result<WalletBalance, Self::Error>;
    async fn get_amount_spent_on_steam(&self) -> Result<String, Self::Error>;
    async fn get_purchase_history(&self) -> Result<Vec<PurchaseHistoryItem>, Self::Error>;
    async fn redeem_wallet_code(&self, code: &str) -> Result<RedeemWalletCodeResponse, Self::Error>;
    async fn parental_unlock(&self, pin: &str) -> Result<(), Self::Error>;

    // =====================================================================
    // Activity
    // =====================================================================

    async fn get_friend_activity(&self, start: Option<u64>) -> Result<FriendActivityResponse, Self::Error>;
    async fn get_friend_activity_full(&self) -> Result<Vec<FriendActivity>, Self::Error>;
    async fn comment_user_received_new_game(&self, steam_id: SteamID, thread_id: u64, comment: &str) -> Result<ActivityCommentResponse, Self::Error>;
    async fn rate_up_user_received_new_game(&self, steam_id: SteamID, thread_id: u64) -> Result<ActivityCommentResponse, Self::Error>;
    async fn delete_comment_user_received_new_game(&self, steam_id: SteamID, thread_id: u64, comment_id: &str) -> Result<ActivityCommentResponse, Self::Error>;

    // =====================================================================
    // Apps
    // =====================================================================

    async fn get_owned_apps(&self) -> Result<Vec<OwnedApp>, Self::Error>;
    async fn get_owned_apps_id(&self) -> Result<Vec<u32>, Self::Error>;
    async fn get_owned_apps_detail(&self) -> Result<Vec<OwnedAppDetail>, Self::Error>;
    async fn get_app_detail(&self, app_ids: &[u32]) -> Result<HashMap<u32, AppDetail>, Self::Error>;
    async fn fetch_csgo_account_stats(&self) -> Result<CsgoAccountStats, Self::Error>;
    async fn get_app_list(&self) -> Result<SimpleSteamAppList, Self::Error>;
    async fn suggest_app_list(&self, term: &str) -> Result<Vec<AppListItem>, Self::Error>;
    async fn query_app_list(&self, term: &str) -> Result<Vec<AppListItem>, Self::Error>;
    async fn get_steam_app_version_info(&self, app_id: u32) -> Result<SteamAppVersionInfo, Self::Error>;
    async fn get_dynamic_store_user_data(&self) -> Result<DynamicStoreUserData, Self::Error>;
    async fn fetch_batched_loyalty_reward_items(&self, app_ids: &[u32]) -> Result<Vec<steam_protos::messages::CLoyaltyRewardsBatchedQueryRewardItemsResponseResponse>, Self::Error>;

    // =====================================================================
    // Comments
    // =====================================================================

    async fn get_my_comments(&self) -> Result<Vec<UserComment>, Self::Error>;
    async fn get_user_comments(&self, steam_id: SteamID) -> Result<Vec<UserComment>, Self::Error>;
    async fn post_comment(&self, steam_id: SteamID, message: &str) -> Result<Option<UserComment>, Self::Error>;
    async fn delete_comment(&self, steam_id: SteamID, gidcomment: &str) -> Result<(), Self::Error>;

    // =====================================================================
    // Confirmations
    // =====================================================================

    async fn get_confirmations(&self, identity_secret: &str, tag: Option<&str>) -> Result<Vec<Confirmation>, Self::Error>;
    async fn accept_confirmation_for_object(&self, identity_secret: &str, object_id: u64) -> Result<(), Self::Error>;
    async fn deny_confirmation_for_object(&self, identity_secret: &str, object_id: u64) -> Result<(), Self::Error>;

    // =====================================================================
    // Email
    // =====================================================================

    async fn get_account_email(&self) -> Result<String, Self::Error>;
    async fn get_current_steam_login(&self) -> Result<String, Self::Error>;

    // =====================================================================
    // Friends
    // =====================================================================

    async fn add_friend(&self, steam_id: SteamID) -> Result<(), Self::Error>;
    async fn remove_friend(&self, steam_id: SteamID) -> Result<(), Self::Error>;
    async fn accept_friend_request(&self, steam_id: SteamID) -> Result<(), Self::Error>;
    async fn ignore_friend_request(&self, steam_id: SteamID) -> Result<(), Self::Error>;
    async fn block_user(&self, steam_id: SteamID) -> Result<(), Self::Error>;
    async fn unblock_user(&self, steam_id: SteamID) -> Result<(), Self::Error>;
    async fn get_friends_list(&self) -> Result<HashMap<SteamID, i32>, Self::Error>;
    async fn get_friends_details(&self) -> Result<FriendListPage, Self::Error>;
    async fn get_friends_details_of_user(&self, steam_id: SteamID) -> Result<FriendListPage, Self::Error>;
    async fn search_users(&self, query: &str, page: u32) -> Result<CommunitySearchResult, Self::Error>;
    async fn create_instant_invite(&self) -> Result<String, Self::Error>;
    async fn follow_user(&self, steam_id: SteamID) -> Result<(), Self::Error>;
    async fn unfollow_user(&self, steam_id: SteamID) -> Result<(), Self::Error>;
    async fn get_following_list(&self) -> Result<FriendListPage, Self::Error>;
    async fn get_following_list_of_user(&self, steam_id: SteamID) -> Result<FriendListPage, Self::Error>;
    async fn get_my_friends_id_list(&self) -> Result<Vec<SteamID>, Self::Error>;
    async fn get_pending_friend_list(&self) -> Result<PendingFriendList, Self::Error>;
    async fn remove_friends(&self, steam_ids: &[SteamID]) -> Result<(), Self::Error>;
    async fn unfollow_users(&self, steam_ids: &[SteamID]) -> Result<(), Self::Error>;
    async fn cancel_friend_request(&self, steam_id: SteamID) -> Result<(), Self::Error>;
    async fn get_friends_in_common(&self, steam_id: SteamID) -> Result<Vec<FriendDetails>, Self::Error>;

    // =====================================================================
    // Groups
    // =====================================================================

    async fn join_group(&self, group_id: SteamID) -> Result<(), Self::Error>;
    async fn leave_group(&self, group_id: SteamID) -> Result<(), Self::Error>;
    async fn get_group_members(&self, group_id: SteamID) -> Result<Vec<SteamID>, Self::Error>;
    async fn post_group_announcement(&self, group_id: SteamID, headline: &str, content: &str) -> Result<(), Self::Error>;
    async fn kick_group_member(&self, group_id: SteamID, member_id: SteamID) -> Result<(), Self::Error>;
    async fn invite_user_to_group(&self, user_id: SteamID, group_id: SteamID) -> Result<(), Self::Error>;
    async fn invite_users_to_group(&self, user_ids: &[SteamID], group_id: SteamID) -> Result<(), Self::Error>;
    async fn accept_group_invite(&self, group_id: SteamID) -> Result<(), Self::Error>;
    async fn ignore_group_invite(&self, group_id: SteamID) -> Result<(), Self::Error>;
    async fn get_group_overview(&self, gid: Option<SteamID>, group_url: Option<&str>, page: Option<i32>, search_key: Option<&str>) -> Result<GroupOverview, Self::Error>;
    async fn get_group_steam_id_from_vanity_url(&self, vanity_url: &str) -> Result<String, Self::Error>;
    async fn get_group_info_xml(&self, gid: Option<SteamID>, group_url: Option<&str>, page: Option<u32>) -> Result<GroupInfoXml, Self::Error>;
    async fn get_group_info_xml_full(&self, gid: Option<SteamID>, group_url: Option<&str>) -> Result<GroupInfoXml, Self::Error>;
    async fn get_invitable_groups(&self, user_steam_id: SteamID) -> Result<Vec<InvitableGroup>, Self::Error>;
    async fn invite_all_friends_to_group(&self, group_id: SteamID) -> Result<(), Self::Error>;

    // =====================================================================
    // Inventory
    // =====================================================================

    async fn get_inventory(&self, appid: AppId, context_id: ContextId) -> Result<Vec<EconItem>, Self::Error>;
    async fn get_user_inventory_contents(&self, steam_id: SteamID, appid: AppId, context_id: ContextId) -> Result<Vec<EconItem>, Self::Error>;
    async fn get_inventory_history(&self) -> Result<InventoryHistoryResult, Self::Error>;
    async fn get_price_overview(&self, appid: AppId, market_hash_name: &str) -> Result<PriceOverview, Self::Error>;
    async fn get_active_inventories(&self) -> Result<Vec<ActiveInventory>, Self::Error>;
    async fn get_inventory_trading(&self, appid: AppId, context_id: ContextId) -> Result<serde_json::Value, Self::Error>;
    async fn get_inventory_trading_partner(&self, appid: AppId, partner: SteamID, context_id: ContextId) -> Result<serde_json::Value, Self::Error>;
    async fn get_full_inventory_history(&self) -> Result<Vec<InventoryHistoryItem>, Self::Error>;

    // =====================================================================
    // Market
    // =====================================================================

    async fn get_my_listings(&self) -> Result<MyListingsResult, Self::Error>;
    async fn get_market_history(&self, start: u32, count: u32) -> Result<MarketHistoryResponse, Self::Error>;
    async fn sell_item(&self, appid: AppId, contextid: ContextId, assetid: AssetId, amount: Amount, price: PriceCents) -> Result<SellItemResult, Self::Error>;
    async fn remove_listing(&self, listing_id: &str) -> Result<bool, Self::Error>;
    async fn get_gem_value(&self, appid: AppId, assetid: AssetId) -> Result<GemValue, Self::Error>;
    async fn turn_item_into_gems(&self, appid: AppId, assetid: AssetId, expected_value: u32) -> Result<GemResult, Self::Error>;
    async fn get_booster_pack_catalog(&self) -> Result<Vec<BoosterPackEntry>, Self::Error>;
    async fn create_booster_pack(&self, appid: AppId, use_untradable_gems: bool) -> Result<BoosterResult, Self::Error>;
    async fn open_booster_pack(&self, appid: AppId, assetid: AssetId) -> Result<Vec<EconItem>, Self::Error>;
    async fn get_market_restrictions(&self) -> Result<(MarketRestrictions, Option<WalletBalance>), Self::Error>;
    async fn get_market_apps(&self) -> Result<HashMap<u32, String>, Self::Error>;
    async fn get_item_nameid(&self, app_id: AppId, market_hash_name: &str) -> Result<ItemNameId, Self::Error>;
    async fn get_item_orders_histogram(&self, item_nameid: ItemNameId, country: &str, currency: u32) -> Result<ItemOrdersHistogramResponse, Self::Error>;

    // =====================================================================
    // Phone
    // =====================================================================

    async fn get_phone_number_status(&self) -> Result<Option<String>, Self::Error>;
    async fn add_phone_number(&self, phone: &str) -> Result<AddPhoneNumberResponse, Self::Error>;
    async fn confirm_phone_code_for_add(&self, code: &str) -> Result<ConfirmPhoneCodeResponse, Self::Error>;
    async fn resend_phone_verification_code(&self) -> Result<serde_json::Value, Self::Error>;
    async fn get_remove_phone_number_type(&self) -> Result<Option<RemovePhoneResult>, Self::Error>;
    async fn send_account_recovery_code(&self, wizard_param: serde_json::Value, method: i32) -> Result<serde_json::Value, Self::Error>;
    async fn confirm_remove_phone_number_code(&self, wizard_param: serde_json::Value, code: &str) -> Result<serde_json::Value, Self::Error>;
    async fn send_confirmation_2_steam_mobile_app(&self, wizard_param: serde_json::Value) -> Result<serde_json::Value, Self::Error>;
    async fn send_confirmation_2_steam_mobile_app_final(&self, wizard_param: serde_json::Value) -> Result<serde_json::Value, Self::Error>;

    // =====================================================================
    // Privacy
    // =====================================================================

    async fn get_privacy_settings(&self) -> Result<PrivacySettings, Self::Error>;
    async fn set_privacy_settings(&self, settings: PrivacySettings) -> Result<PrivacySettings, Self::Error>;
    async fn set_all_privacy(&self, level: &str) -> Result<PrivacySettings, Self::Error>;

    // =====================================================================
    // Profile
    // =====================================================================

    async fn get_profile(&self, steam_id: Option<SteamID>) -> Result<SteamProfile, Self::Error>;
    #[deprecated(note = "scraper is !Send; call SteamUser::edit_profile() directly instead of using this trait method")]
    async fn edit_profile(&self, settings: serde_json::Value) -> Result<(), Self::Error>;
    async fn set_persona_name(&self, name: &str) -> Result<(), Self::Error>;
    async fn get_alias_history(&self, steam_id: SteamID) -> Result<Vec<AliasEntry>, Self::Error>;
    async fn clear_previous_aliases(&self) -> Result<(), Self::Error>;
    async fn set_nickname(&self, steam_id: SteamID, nickname: &str) -> Result<(), Self::Error>;
    async fn remove_nickname(&self, steam_id: SteamID) -> Result<(), Self::Error>;
    async fn post_profile_status(&self, text: &str, app_id: Option<u32>) -> Result<u64, Self::Error>;
    async fn select_previous_avatar(&self, avatar_hash: &str) -> Result<(), Self::Error>;
    async fn setup_profile(&self) -> Result<bool, Self::Error>;
    async fn get_user_summary_from_xml(&self, steam_id: SteamID) -> Result<UserSummaryXml, Self::Error>;
    async fn get_user_summary_from_profile(&self, steam_id: Option<SteamID>) -> Result<UserSummaryProfile, Self::Error>;
    #[deprecated(note = "scraper is !Send; call SteamUser::fetch_full_profile() directly instead of using this trait method")]
    async fn fetch_full_profile(&self, steam_id: SteamID) -> Result<SteamProfile, Self::Error>;
    async fn resolve_user(&self, steam_id: SteamID) -> Result<Option<SteamUserProfile>, Self::Error>;
    async fn get_avatar_history(&self) -> Result<Vec<AvatarHistoryEntry>, Self::Error>;
    async fn upload_avatar_from_url(&self, url: &str) -> Result<AvatarUploadResponse, Self::Error>;

    // =====================================================================
    // Tokens
    // =====================================================================

    async fn enumerate_tokens(&self) -> Result<steam_protos::CAuthenticationRefreshTokenEnumerateResponse, Self::Error>;
    async fn check_token_exists(&self, token_id: &str) -> Result<bool, Self::Error>;
    async fn revoke_tokens(&self, token_ids: &[&str], shared_secret: Option<&str>) -> Result<crate::services::tokens::RevokeTokensResult, Self::Error>;

    // =====================================================================
    // Trade
    // =====================================================================

    async fn get_trade_url(&self) -> Result<Option<String>, Self::Error>;
    async fn get_trade_offer(&self) -> Result<TradeOffersResponse, Self::Error>;
    async fn accept_trade_offer(&self, trade_offer_id: u64, partner_steam_id: Option<String>) -> Result<String, Self::Error>;
    async fn decline_trade_offer(&self, trade_offer_id: u64) -> Result<(), Self::Error>;
    async fn send_trade_offer(&self, trade_url: &str, my_assets: Vec<TradeOfferAsset>, their_assets: Vec<TradeOfferAsset>, message: &str) -> Result<TradeOfferResult, Self::Error>;

    // =====================================================================
    // Two-Factor Authentication
    // =====================================================================

    async fn get_steam_guard_status(&self) -> Result<SteamGuardStatus, Self::Error>;
    async fn enable_two_factor(&self) -> Result<TwoFactorResponse, Self::Error>;
    async fn finalize_two_factor(&self, shared_secret: &str, activation_code: &str) -> Result<(), Self::Error>;
    async fn disable_two_factor(&self, revocation_code: &str) -> Result<(), Self::Error>;
    async fn deauthorize_devices(&self) -> Result<(), Self::Error>;
    async fn add_authenticator(&self) -> Result<TwoFactorResponse, Self::Error>;
    async fn finalize_authenticator(&self, activation_code: &str) -> Result<(), Self::Error>;
    async fn remove_authenticator(&self, revocation_code: &str) -> Result<(), Self::Error>;
    async fn enable_steam_guard_email(&self) -> Result<bool, Self::Error>;
    async fn disable_steam_guard_email(&self) -> Result<bool, Self::Error>;

    // =====================================================================
    // Extra (reports, license, help, match history)
    // =====================================================================

    async fn get_player_reports(&self) -> Result<Vec<PlayerReport>, Self::Error>;
    async fn add_free_license(&self, package_id: u32) -> Result<bool, Self::Error>;
    async fn add_sub_free_license(&self, sub_id: u32) -> Result<bool, Self::Error>;
    async fn redeem_points(&self, definition_id: u32) -> Result<steam_protos::messages::loyalty_rewards::CLoyaltyRewardsRedeemPointsResponse, Self::Error>;
    async fn get_help_requests(&self) -> Result<Vec<HelpRequest>, Self::Error>;
    async fn get_help_request_detail(&self, id: &str) -> Result<String, Self::Error>;
    async fn get_match_history(&self, match_type: &str, token: Option<&str>) -> Result<MatchHistoryResponse, Self::Error>;

    // =====================================================================
    // Misc (notifications, web API, etc.)
    // =====================================================================

    async fn logged_in(&self) -> Result<LoggedInResult, Self::Error>;
    async fn get_notifications(&self) -> Result<Notifications, Self::Error>;
    #[deprecated(note = "scraper is !Send; call SteamUser::get_web_api_key() directly instead of using this trait method")]
    async fn get_web_api_key(&self, domain: &str) -> Result<String, Self::Error>;
    async fn resolve_vanity_url(&self, api_key: &str, vanity_name: &str) -> Result<SteamID, Self::Error>;
    async fn revoke_web_api_key(&self) -> Result<(), Self::Error>;
}