--- a/src/api/workshop.rs 2026-09-18 16:42:37.406700437 +0000 +++ b/src/api/workshop.rs 2026-09-18 16:42:37.406700437 +0000 @@ -108,6 +108,13 @@ pub total: BigInt, } + #[napi(object)] + pub struct UserItemVote { + pub voted_up: bool, + pub voted_down: bool, + pub vote_skipped: bool, + } + #[derive(Debug)] #[napi] pub enum UpdateStatus { @@ -319,6 +326,52 @@ Err(e) => Err(Error::from_reason(e.to_string())), } } + + /// Sets the current user's vote (up or down) on a workshop item. + /// + /// {@link https://partner.steamgames.com/doc/api/ISteamUGC#SetUserItemVote} + #[napi] + pub async fn vote_item(item_id: BigInt, vote_up: bool) -> Result<(), Error> { + let client = crate::client::get_client(); + let (tx, rx) = oneshot::channel(); + + client + .ugc() + .vote_up_item(PublishedFileId(item_id.get_u64().1), vote_up, |result| { + tx.send(result).unwrap(); + }); + + let result = rx.await.unwrap(); + match result { + Ok(()) => Ok(()), + Err(e) => Err(Error::from_reason(e.to_string())), + } + } + + /// Gets the current user's existing vote (if any) on a workshop item. + /// + /// {@link https://partner.steamgames.com/doc/api/ISteamUGC#GetUserItemVote} + #[napi] + pub async fn get_user_vote(item_id: BigInt) -> Result { + let client = crate::client::get_client(); + let (tx, rx) = oneshot::channel(); + + client + .ugc() + .user_item_vote(PublishedFileId(item_id.get_u64().1), |result| { + tx.send(result).unwrap(); + }); + + let result = rx.await.unwrap(); + match result { + Ok(v) => Ok(UserItemVote { + voted_up: v.voted_up, + voted_down: v.voted_down, + vote_skipped: v.vote_skipped, + }), + Err(e) => Err(Error::from_reason(e.to_string())), + } + } /// Gets the current state of a workshop item on this client. States can be combined. ///