From c3c993624a3fd5311b4bddc89131fd4bf389d9f7 Mon Sep 17 00:00:00 2001 From: Stephen Leitnick Date: Thu, 28 Mar 2024 16:08:17 -0400 Subject: [PATCH 1/5] Get subscription --- examples/datastore-get-entry.rs | 5 +- examples/group-get-shout.rs | 5 +- examples/publish-message.rs | 5 +- examples/publish-place.rs | 5 +- src/cli/datastore_cli.rs | 11 +++-- src/cli/experience_cli.rs | 5 +- src/cli/group_cli.rs | 2 +- src/cli/messaging_cli.rs | 2 +- src/cli/mod.rs | 6 +++ src/cli/ordered_datastore_cli.rs | 9 ++-- src/cli/subscription_cli.rs | 78 ++++++++++++++++++++++++++++++++ src/rbx/mod.rs | 1 + src/rbx/types.rs | 21 +++++++++ src/rbx/v1/mod.rs | 19 +------- src/rbx/v2/group.rs | 5 +- src/rbx/v2/mod.rs | 43 ++++++++++++++++-- src/rbx/v2/subscription.rs | 70 ++++++++++++++++++++++++++++ 17 files changed, 246 insertions(+), 46 deletions(-) create mode 100644 src/cli/subscription_cli.rs create mode 100644 src/rbx/types.rs create mode 100644 src/rbx/v2/subscription.rs diff --git a/examples/datastore-get-entry.rs b/examples/datastore-get-entry.rs index 3b72aa1..d6a5da7 100644 --- a/examples/datastore-get-entry.rs +++ b/examples/datastore-get-entry.rs @@ -1,4 +1,7 @@ -use rbxcloud::rbx::v1::{DataStoreGetEntry, RbxCloud, UniverseId}; +use rbxcloud::rbx::{ + types::UniverseId, + v1::{DataStoreGetEntry, RbxCloud}, +}; #[tokio::main] async fn main() { diff --git a/examples/group-get-shout.rs b/examples/group-get-shout.rs index 3f65d52..c961e23 100644 --- a/examples/group-get-shout.rs +++ b/examples/group-get-shout.rs @@ -1,7 +1,4 @@ -use rbxcloud::rbx::{ - error::Error, - v2::{group::GroupId, Client}, -}; +use rbxcloud::rbx::{error::Error, types::GroupId, v2::Client}; async fn get_group_shout() -> Result { // Inputs: diff --git a/examples/publish-message.rs b/examples/publish-message.rs index 43a1dba..93df855 100644 --- a/examples/publish-message.rs +++ b/examples/publish-message.rs @@ -1,7 +1,4 @@ -use rbxcloud::rbx::{ - error::Error, - v1::{RbxCloud, UniverseId}, -}; +use rbxcloud::rbx::{error::Error, types::UniverseId, v1::RbxCloud}; async fn publish_message() -> Result<(), Error> { // Inputs: diff --git a/examples/publish-place.rs b/examples/publish-place.rs index b589c31..f39d27f 100644 --- a/examples/publish-place.rs +++ b/examples/publish-place.rs @@ -1,4 +1,7 @@ -use rbxcloud::rbx::v1::{PlaceId, PublishVersionType, RbxCloud, UniverseId}; +use rbxcloud::rbx::{ + types::{PlaceId, UniverseId}, + v1::{PublishVersionType, RbxCloud}, +}; #[tokio::main] async fn main() { diff --git a/src/cli/datastore_cli.rs b/src/cli/datastore_cli.rs index 0341c9b..fbf01ca 100644 --- a/src/cli/datastore_cli.rs +++ b/src/cli/datastore_cli.rs @@ -1,9 +1,12 @@ use clap::{Args, Subcommand, ValueEnum}; -use rbxcloud::rbx::v1::{ - DataStoreDeleteEntry, DataStoreGetEntry, DataStoreGetEntryVersion, DataStoreIncrementEntry, - DataStoreListEntries, DataStoreListEntryVersions, DataStoreListStores, DataStoreSetEntry, - RbxCloud, ReturnLimit, RobloxUserId, UniverseId, +use rbxcloud::rbx::{ + types::{ReturnLimit, RobloxUserId, UniverseId}, + v1::{ + DataStoreDeleteEntry, DataStoreGetEntry, DataStoreGetEntryVersion, DataStoreIncrementEntry, + DataStoreListEntries, DataStoreListEntryVersions, DataStoreListStores, DataStoreSetEntry, + RbxCloud, + }, }; #[derive(Debug, Subcommand)] diff --git a/src/cli/experience_cli.rs b/src/cli/experience_cli.rs index 37b9015..0db9352 100644 --- a/src/cli/experience_cli.rs +++ b/src/cli/experience_cli.rs @@ -1,6 +1,9 @@ use clap::{Args, Subcommand, ValueEnum}; -use rbxcloud::rbx::v1::{PlaceId, PublishVersionType, RbxCloud, UniverseId}; +use rbxcloud::rbx::{ + types::{PlaceId, UniverseId}, + v1::{PublishVersionType, RbxCloud}, +}; #[derive(Debug, Subcommand)] pub enum ExperienceCommands { diff --git a/src/cli/group_cli.rs b/src/cli/group_cli.rs index 93b21a3..bddf054 100644 --- a/src/cli/group_cli.rs +++ b/src/cli/group_cli.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use rbxcloud::rbx::v2::{group::GroupId, Client}; +use rbxcloud::rbx::{types::GroupId, v2::Client}; #[derive(Debug, Subcommand)] pub enum GroupCommands { diff --git a/src/cli/messaging_cli.rs b/src/cli/messaging_cli.rs index 9d32bb1..705b873 100644 --- a/src/cli/messaging_cli.rs +++ b/src/cli/messaging_cli.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use rbxcloud::rbx::v1::{RbxCloud, UniverseId}; +use rbxcloud::rbx::{types::UniverseId, v1::RbxCloud}; #[derive(Debug, Subcommand)] pub enum MessagingCommands { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 1938b34..aa254c5 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -4,12 +4,14 @@ mod experience_cli; mod group_cli; mod messaging_cli; mod ordered_datastore_cli; +mod subscription_cli; use clap::{Parser, Subcommand}; use self::{ assets_cli::Assets, datastore_cli::DataStore, experience_cli::Experience, group_cli::Group, messaging_cli::Messaging, ordered_datastore_cli::OrderedDataStore, + subscription_cli::Subscription, }; #[derive(Debug, Parser)] @@ -38,6 +40,9 @@ pub enum Command { /// Access the Roblox Group API Group(Group), + + /// Access the Roblox Subscription API + Subscription(Subscription), } impl Cli { @@ -49,6 +54,7 @@ impl Cli { Command::Datastore(command) => command.run().await, Command::OrderedDatastore(command) => command.run().await, Command::Group(command) => command.run().await, + Command::Subscription(command) => command.run().await, } } } diff --git a/src/cli/ordered_datastore_cli.rs b/src/cli/ordered_datastore_cli.rs index cd0baa0..eecd4d3 100644 --- a/src/cli/ordered_datastore_cli.rs +++ b/src/cli/ordered_datastore_cli.rs @@ -1,7 +1,10 @@ use clap::{Args, Subcommand}; -use rbxcloud::rbx::v1::{ - OrderedDataStoreCreateEntry, OrderedDataStoreEntry, OrderedDataStoreIncrementEntry, - OrderedDataStoreListEntries, OrderedDataStoreUpdateEntry, RbxCloud, UniverseId, +use rbxcloud::rbx::{ + types::UniverseId, + v1::{ + OrderedDataStoreCreateEntry, OrderedDataStoreEntry, OrderedDataStoreIncrementEntry, + OrderedDataStoreListEntries, OrderedDataStoreUpdateEntry, RbxCloud, + }, }; #[derive(Debug, Subcommand)] diff --git a/src/cli/subscription_cli.rs b/src/cli/subscription_cli.rs new file mode 100644 index 0000000..f3569f4 --- /dev/null +++ b/src/cli/subscription_cli.rs @@ -0,0 +1,78 @@ +use clap::{Args, Subcommand}; +use rbxcloud::rbx::{ + types::UniverseId, + v2::{subscription::SubscriptionView, Client}, +}; + +#[derive(Debug, Subcommand)] +pub enum SubscriptionCommands { + /// Get information about a subscription + Get { + /// Universe ID + #[clap(short, long, value_parser)] + universe_id: u64, + + /// Subscription product ID + #[clap(short, long, value_parser)] + subscription_product: String, + + /// Subscription ID + #[clap(short, long, value_parser)] + subscription: String, + + /// View type + #[clap(short, long, value_enum)] + view: Option, + + /// Pretty-print the JSON response + #[clap(short, long, value_parser, default_value_t = false)] + pretty: bool, + + /// Roblox Open Cloud API Key + #[clap(short, long, value_parser, env = "RBXCLOUD_API_KEY")] + api_key: String, + }, +} + +#[derive(Debug, Args)] +pub struct Subscription { + #[clap(subcommand)] + command: SubscriptionCommands, +} + +impl Subscription { + pub async fn run(self) -> anyhow::Result> { + match self.command { + SubscriptionCommands::Get { + universe_id, + subscription_product, + subscription, + view, + pretty, + api_key, + } => { + let client = Client::new(&api_key); + let subscription_client = client.subscription(); + let res = subscription_client + .get( + UniverseId(universe_id), + subscription_product, + subscription, + view, + ) + .await; + match res { + Ok(subscription_info) => { + let r = if pretty { + serde_json::to_string_pretty(&subscription_info)? + } else { + serde_json::to_string(&subscription_info)? + }; + Ok(Some(r)) + } + Err(err) => Err(anyhow::anyhow!(err)), + } + } + } + } +} diff --git a/src/rbx/mod.rs b/src/rbx/mod.rs index 767d4de..5fa4be1 100644 --- a/src/rbx/mod.rs +++ b/src/rbx/mod.rs @@ -2,6 +2,7 @@ //! //! Most usage should go through the `RbxCloud` struct. pub mod error; +pub mod types; pub(crate) mod util; pub mod v1; pub mod v2; diff --git a/src/rbx/types.rs b/src/rbx/types.rs new file mode 100644 index 0000000..aee3e99 --- /dev/null +++ b/src/rbx/types.rs @@ -0,0 +1,21 @@ +/// Represents the UniverseId of a Roblox experience. +#[derive(Debug, Clone, Copy)] +pub struct UniverseId(pub u64); + +/// Represents the PlaceId of a specific place within a Roblox experience. +#[derive(Debug, Clone, Copy)] +pub struct PlaceId(pub u64); + +// Number of items to return. +#[derive(Debug, Clone, Copy)] +pub struct ReturnLimit(pub u64); + +/// Represents a Roblox user's ID. +#[derive(Debug, Clone, Copy)] +pub struct RobloxUserId(pub u64); + +#[derive(Debug, Clone, Copy)] +pub struct PageSize(pub u64); + +#[derive(Debug, Clone, Copy)] +pub struct GroupId(pub u64); diff --git a/src/rbx/v1/mod.rs b/src/rbx/v1/mod.rs index c2dea12..e952b06 100644 --- a/src/rbx/v1/mod.rs +++ b/src/rbx/v1/mod.rs @@ -31,24 +31,7 @@ use self::{ }, }; -/// Represents the UniverseId of a Roblox experience. -#[derive(Debug, Clone, Copy)] -pub struct UniverseId(pub u64); - -/// Represents the PlaceId of a specific place within a Roblox experience. -#[derive(Debug, Clone, Copy)] -pub struct PlaceId(pub u64); - -// Number of items to return. -#[derive(Debug, Clone, Copy)] -pub struct ReturnLimit(pub u64); - -/// Represents a Roblox user's ID. -#[derive(Debug, Clone, Copy)] -pub struct RobloxUserId(pub u64); - -#[derive(Debug, Clone, Copy)] -pub struct PageSize(pub u64); +use super::types::{PageSize, PlaceId, ReturnLimit, RobloxUserId, UniverseId}; impl std::fmt::Display for UniverseId { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { diff --git a/src/rbx/v2/group.rs b/src/rbx/v2/group.rs index 4b223ff..b31d079 100644 --- a/src/rbx/v2/group.rs +++ b/src/rbx/v2/group.rs @@ -1,12 +1,9 @@ use serde::{Deserialize, Serialize}; -use crate::rbx::{error::Error, util::QueryString}; +use crate::rbx::{error::Error, types::GroupId, util::QueryString}; use super::http_err::handle_http_err; -#[derive(Debug, Clone, Copy)] -pub struct GroupId(pub u64); - impl std::fmt::Display for GroupId { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.0) diff --git a/src/rbx/v2/mod.rs b/src/rbx/v2/mod.rs index 8c4ba16..b6cfb4d 100644 --- a/src/rbx/v2/mod.rs +++ b/src/rbx/v2/mod.rs @@ -2,16 +2,22 @@ //! //! Most usage should go through the `Client` struct. -use self::group::{ - GetGroupParams, GetGroupResponse, GetGroupShoutParams, GetGroupShoutResponse, GroupId, - ListGroupMembershipsParams, ListGroupMembershipsResponse, ListGroupRolesParams, - ListGroupRolesResponse, +use self::{ + group::{ + GetGroupParams, GetGroupResponse, GetGroupShoutParams, GetGroupShoutResponse, + ListGroupMembershipsParams, ListGroupMembershipsResponse, ListGroupRolesParams, + ListGroupRolesResponse, + }, + subscription::{GetSubscriptionParams, GetSubscriptionResponse, SubscriptionView}, }; pub mod group; pub(crate) mod http_err; +pub mod subscription; use crate::rbx::error::Error; +use super::types::{GroupId, UniverseId}; + /// Access into the Roblox Open Cloud APIs. /// /// ```rust,no_run @@ -30,6 +36,10 @@ pub struct GroupClient { pub group_id: GroupId, } +pub struct SubscriptionClient { + pub api_key: String, +} + impl GroupClient { pub async fn get_info(&self) -> Result { group::get_group(&GetGroupParams { @@ -78,6 +88,25 @@ impl GroupClient { } } +impl SubscriptionClient { + pub async fn get( + &self, + universe_id: UniverseId, + subscription_product: String, + subscription: String, + view: Option, + ) -> Result { + subscription::get_subscription(&GetSubscriptionParams { + api_key: self.api_key.clone(), + universe_id, + subscription, + subscription_product, + view, + }) + .await + } +} + impl Client { pub fn new(api_key: &str) -> Client { Client { @@ -91,4 +120,10 @@ impl Client { group_id, } } + + pub fn subscription(&self) -> SubscriptionClient { + SubscriptionClient { + api_key: self.api_key.clone(), + } + } } diff --git a/src/rbx/v2/subscription.rs b/src/rbx/v2/subscription.rs new file mode 100644 index 0000000..5112e8a --- /dev/null +++ b/src/rbx/v2/subscription.rs @@ -0,0 +1,70 @@ +use serde::{Deserialize, Serialize}; + +use crate::rbx::{error::Error, types::UniverseId, util::QueryString}; + +use super::http_err::handle_http_err; + +#[derive(Debug, Clone, Copy, clap::ValueEnum)] +pub enum SubscriptionView { + Basic, + Full, +} + +impl std::fmt::Display for SubscriptionView { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!( + f, + "{:?}", + match self { + Self::Basic => "BASIC", + Self::Full => "FULL", + } + ) + } +} + +pub struct GetSubscriptionParams { + pub api_key: String, + pub universe_id: UniverseId, + pub subscription_product: String, + pub subscription: String, + pub view: Option, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetSubscriptionResponse {} + +pub async fn get_subscription( + params: &GetSubscriptionParams, +) -> Result { + let client = reqwest::Client::new(); + + let url = format!( + "https://apis.roblox.com/cloud/v2/universes/{universeId}/subscription-products/{subscription}", + universeId = ¶ms.universe_id, + subscription = ¶ms.subscription_product, + ); + + let mut query: QueryString = vec![]; + if let Some(view) = ¶ms.view { + query.push(("view", view.to_string())) + } + + let res = client + .get(url) + .header("x-api-key", ¶ms.api_key) + .query(&query) + .send() + .await?; + + let status = res.status(); + + if !status.is_success() { + let code = status.as_u16(); + return handle_http_err(code); + } + + let body = res.json::().await?; + Ok(body) +} From 88b104e71808ecf267051b617d9ecb09a54e690b Mon Sep 17 00:00:00 2001 From: Stephen Leitnick Date: Thu, 28 Mar 2024 16:14:22 -0400 Subject: [PATCH 2/5] Example --- docs/cli/cli-group.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/cli/cli-group.md b/docs/cli/cli-group.md index f3bd06d..d47d4db 100644 --- a/docs/cli/cli-group.md +++ b/docs/cli/cli-group.md @@ -74,3 +74,8 @@ Options: -n, --next-page-token Next page token -h, --help Print help ``` + +### Example +``` +$ rbxcloud group memberships -p -g 12345 -a MY_KEY +``` From bc62c6e0ef995d19414d55a26d3862756fb8a369 Mon Sep 17 00:00:00 2001 From: Stephen Leitnick Date: Thu, 28 Mar 2024 16:15:06 -0400 Subject: [PATCH 3/5] Subscription docs --- docs/cli/cli-subscription.md | 20 ++++++++++++++++++++ mkdocs.yml | 1 + src/cli/subscription_cli.rs | 13 ++++--------- 3 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 docs/cli/cli-subscription.md diff --git a/docs/cli/cli-subscription.md b/docs/cli/cli-subscription.md new file mode 100644 index 0000000..16084bb --- /dev/null +++ b/docs/cli/cli-subscription.md @@ -0,0 +1,20 @@ +# Subscription API + +## Getting Subscription Info +``` +Usage: rbxcloud.exe subscription get [OPTIONS] --universe-id --product --subscription --api-key + +Options: + -u, --universe-id Universe ID + -S, --product Subscription product ID + -s, --subscription Subscription ID + -v, --view View type [possible values: basic, full] + -p, --pretty Pretty-print the JSON response + -a, --api-key Roblox Open Cloud API Key [env: RBXCLOUD_API_KEY=] + -h, --help Print help +``` + +### Example +``` +$ rbxcloud subscription get -p -u 12345 -S 1234 -s 5678 -a MY_KEY +``` diff --git a/mkdocs.yml b/mkdocs.yml index 3d7e611..f8c8122 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -14,6 +14,7 @@ nav: - DataStore: cli/cli-datastore.md - OrderedDataStore: cli/cli-ordered-datastore.md - Group: cli/cli-group.md + - Subscription: cli/cli-subscription.md - Rust Lib: - Install: lib/lib-install.md diff --git a/src/cli/subscription_cli.rs b/src/cli/subscription_cli.rs index f3569f4..bf34ca8 100644 --- a/src/cli/subscription_cli.rs +++ b/src/cli/subscription_cli.rs @@ -13,8 +13,8 @@ pub enum SubscriptionCommands { universe_id: u64, /// Subscription product ID - #[clap(short, long, value_parser)] - subscription_product: String, + #[clap(short = 'S', long, value_parser)] + product: String, /// Subscription ID #[clap(short, long, value_parser)] @@ -45,7 +45,7 @@ impl Subscription { match self.command { SubscriptionCommands::Get { universe_id, - subscription_product, + product, subscription, view, pretty, @@ -54,12 +54,7 @@ impl Subscription { let client = Client::new(&api_key); let subscription_client = client.subscription(); let res = subscription_client - .get( - UniverseId(universe_id), - subscription_product, - subscription, - view, - ) + .get(UniverseId(universe_id), product, subscription, view) .await; match res { Ok(subscription_info) => { From c41308b7f2f3cffc3dfb52ca7323e3f7d0096e5b Mon Sep 17 00:00:00 2001 From: Stephen Leitnick Date: Thu, 28 Mar 2024 16:17:16 -0400 Subject: [PATCH 4/5] Bump version --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 6 +++--- docs/cli/cli-install.md | 4 ++-- docs/lib/lib-install.md | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a2c5b8d..2f5136d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -660,7 +660,7 @@ dependencies = [ [[package]] name = "rbxcloud" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "base64 0.22.0", diff --git a/Cargo.toml b/Cargo.toml index 622b3aa..631e54e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rbxcloud" -version = "0.8.0" +version = "0.9.0" description = "CLI and SDK for the Roblox Open Cloud APIs" authors = ["Stephen Leitnick"] license = "MIT" diff --git a/README.md b/README.md index b7ee37a..14d2ae3 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Possible use-cases: | :x: | Universes | | :x: | Places | | :x: | Instances | -| :x: | Subscriptions | +| :white_check_mark: | Subscriptions | | :x: | Inventory | | :x: | User Notifications | @@ -42,7 +42,7 @@ The goal of this project is to support all API endpoints that Roblox provides. ### Aftman Run the `aftman add` command within your project directory. This will add `rbxcloud` to the project's `aftman.toml` file (or create one if it doesn't yet exist). ```sh -$ aftman add Sleitnick/rbxcloud@0.8.0 +$ aftman add Sleitnick/rbxcloud@0.9.0 ``` ### From Release @@ -59,7 +59,7 @@ The library built for the CLI tool is available to use directly in Rust projects To use `rbxcloud` in a Rust project, simply add `rbxcloud` to the `Cargo.toml` dependency list. ```toml [dependencies] -rbxcloud = "0.8.0" +rbxcloud = "0.9.0" ``` Alternatively, use `cargo add`. diff --git a/docs/cli/cli-install.md b/docs/cli/cli-install.md index d6574ef..d3e2bc8 100644 --- a/docs/cli/cli-install.md +++ b/docs/cli/cli-install.md @@ -7,7 +7,7 @@ There are a few different ways to install the `rbxcloud` CLI. ### [Aftman](https://github.com/LPGhatguy/aftman) (Preferred) Run the `aftman add` command within your project directory. This will add `rbxcloud` to the project's `aftman.toml` file (or create one if it doesn't yet exist). ```sh -$ aftman add Sleitnick/rbxcloud@0.8.0 +$ aftman add Sleitnick/rbxcloud@0.9.0 ``` Next, run `aftman install` to install `rbxcloud`. @@ -17,7 +17,7 @@ Add `rbxcloud` under the `[tools]` section of your `foreman.toml` file. ```toml # foreman.toml [tools] -rbxcloud = { github = "Sleitnick/rbxcloud", version = "0.8.0" } +rbxcloud = { github = "Sleitnick/rbxcloud", version = "0.9.0" } ``` Next, run `foreman install` to install `rbxcloud`. diff --git a/docs/lib/lib-install.md b/docs/lib/lib-install.md index cfe7236..33d4a36 100644 --- a/docs/lib/lib-install.md +++ b/docs/lib/lib-install.md @@ -5,7 +5,7 @@ To use `rbxcloud` in a Rust project, simply add `rbxcloud` to the `Cargo.toml` dependency list. ```toml [dependencies] -rbxcloud = "0.8.0" +rbxcloud = "0.9.0" ``` Alternatively, use `cargo add`. From 41b6d8e4d43c895fd55074eb052b47e9a6cd72fa Mon Sep 17 00:00:00 2001 From: Stephen Leitnick Date: Thu, 28 Mar 2024 16:21:28 -0400 Subject: [PATCH 5/5] Docs --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index db53c6f..d15b328 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ //! //! Example: Publishing a message. //! ```rust,no_run -//! use rbxcloud::rbx::{error::Error, v1::{RbxCloud, UniverseId}}; +//! use rbxcloud::rbx::{error::Error, v1::RbxCloud, types::UniverseId}; //! //! async fn publish_message() -> Result<(), Error> { //! let api_key = "my_api_key";