From 6c9bd34f468f314fd2a2b22358e434433da5b40f Mon Sep 17 00:00:00 2001 From: Stephen Leitnick Date: Fri, 21 Mar 2025 14:59:11 -0400 Subject: [PATCH 1/6] Luau execution impl --- src/rbx/types.rs | 6 +- src/rbx/v2/luau_execution.rs | 209 +++++++++++++++++++++++++++++++++++ src/rbx/v2/mod.rs | 1 + 3 files changed, 214 insertions(+), 2 deletions(-) create mode 100644 src/rbx/v2/luau_execution.rs diff --git a/src/rbx/types.rs b/src/rbx/types.rs index aee3e99..81eea6c 100644 --- a/src/rbx/types.rs +++ b/src/rbx/types.rs @@ -1,9 +1,11 @@ +use serde::{Deserialize, Serialize}; + /// Represents the UniverseId of a Roblox experience. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub struct UniverseId(pub u64); /// Represents the PlaceId of a specific place within a Roblox experience. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub struct PlaceId(pub u64); // Number of items to return. diff --git a/src/rbx/v2/luau_execution.rs b/src/rbx/v2/luau_execution.rs new file mode 100644 index 0000000..9498e19 --- /dev/null +++ b/src/rbx/v2/luau_execution.rs @@ -0,0 +1,209 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +use crate::rbx::{ + error::Error, + types::{PlaceId, UniverseId}, +}; + +use super::http_err::handle_http_err; + +#[derive(Debug)] +pub struct CreateLuauExecutionTaskParams { + pub api_key: String, + pub universe_id: UniverseId, + pub place_id: PlaceId, + pub version_id: Option, + pub script: String, + pub timeout: Option, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct NewLuauExecutionSessionTask { + pub path: String, + pub user: String, + pub state: LuauExecutionState, + pub script: String, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetLuauExecutionSessionTaskParams { + pub path: String, + pub api_key: String, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetLuauExecutionSessionTaskLogsParams { + pub path: String, + pub api_key: String, + pub max_page_size: Option, + pub page_token: Option, + pub view: LuauExecutionTaskLogView, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum LuauExecutionTaskLogView { + Flat, + Structured, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct LuauExecutionSessionTaskLogPage { + pub luau_execution_session_task_logs: Vec, + pub next_page_token: String, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct LuauExecutionSessionTaskLog { + pub path: String, + pub messages: Vec, + pub structured_messages: Vec, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct StructuredMessage { + pub message: String, + pub create_time: String, + pub message_type: String, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct LuauExecutionSessionTask { + pub path: String, + pub create_time: String, + pub update_time: String, + pub user: String, + pub state: LuauExecutionState, + pub output: LuauExecutionOutput, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct LuauExecutionOutput { + pub results: Vec, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum LuauExecutionState { + StateUnspecified, + Queued, + Processing, + Cancelled, + Complete, + Failed, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +struct LuauExecutionInput { + pub script: String, + pub timeout: Option, +} + +pub async fn create_luau_execution_task( + params: &CreateLuauExecutionTaskParams, +) -> Result { + let client = reqwest::Client::new(); + + let url = if let Some(version_id) = ¶ms.version_id { + format!( + "https://apis.roblox.com/cloud/v2/universes/{universeId}/places/{placeId}/versions/{versionId}/luau-execution-session-tasks", + universeId = ¶ms.universe_id, + placeId = ¶ms.place_id, + versionId = version_id, + ) + } else { + format!( + "https://apis.roblox.com/cloud/v2/universes/{universeId}/places/{placeId}/luau-execution-session-tasks", + universeId = ¶ms.universe_id, + placeId = ¶ms.place_id, + ) + }; + + let input = LuauExecutionInput { + script: params.script.clone(), + timeout: params.timeout.clone(), + }; + + let req_body = serde_json::to_string(&input)?; + + let res = client + .post(url) + .header("x-api-key", ¶ms.api_key) + .body(req_body) + .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) +} + +pub async fn get_luau_execution_task( + params: &GetLuauExecutionSessionTaskParams, +) -> Result { + let client = reqwest::Client::new(); + + let url = format!( + "https://apis.roblox.com/cloud/v2/{path}", + path = ¶ms.path + ); + + let res = client + .get(url) + .header("x-api-key", ¶ms.api_key) + .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) +} + +pub async fn get_luau_execution_task_logs( + params: &GetLuauExecutionSessionTaskLogsParams, +) -> Result { + let client = reqwest::Client::new(); + + let url = format!( + "https://apis.roblox.com/cloud/v2/{path}", + path = ¶ms.path + ); + + let res = client + .get(url) + .header("x-api-key", ¶ms.api_key) + .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) +} diff --git a/src/rbx/v2/mod.rs b/src/rbx/v2/mod.rs index 6c5d4d3..81be640 100644 --- a/src/rbx/v2/mod.rs +++ b/src/rbx/v2/mod.rs @@ -23,6 +23,7 @@ use self::{ }; pub mod group; pub(crate) mod http_err; +pub mod luau_execution; pub mod notification; pub mod place; pub mod subscription; From 4c5ec24257b83456bb84950245ba388847d35213 Mon Sep 17 00:00:00 2001 From: Stephen Leitnick Date: Fri, 21 Mar 2025 15:06:44 -0400 Subject: [PATCH 2/6] Luau execution client impl --- src/rbx/v2/mod.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/rbx/v2/mod.rs b/src/rbx/v2/mod.rs index 81be640..fb843c4 100644 --- a/src/rbx/v2/mod.rs +++ b/src/rbx/v2/mod.rs @@ -2,6 +2,11 @@ //! //! Most usage should go through the `Client` struct. +use luau_execution::{ + CreateLuauExecutionTaskParams, GetLuauExecutionSessionTaskLogsParams, + GetLuauExecutionSessionTaskParams, LuauExecutionSessionTask, LuauExecutionSessionTaskLogPage, + LuauExecutionTaskLogView, NewLuauExecutionSessionTask, +}; use place::{GetPlaceParams, PlaceInfo, UpdatePlaceInfo, UpdatePlaceParams}; use universe::{ GetUniverseParams, RestartUniverseServersParams, UniverseInfo, UpdateUniverseInfo, @@ -52,6 +57,13 @@ pub struct GroupClient { pub group_id: GroupId, } +pub struct LuauExecutionClient { + pub api_key: String, + pub universe_id: UniverseId, + pub place_id: PlaceId, + pub version_id: Option, +} + pub struct SubscriptionClient { pub api_key: String, } @@ -124,6 +136,49 @@ impl GroupClient { } } +impl LuauExecutionClient { + pub async fn create_task( + &self, + script: String, + timeout: Option, + ) -> Result { + luau_execution::create_luau_execution_task(&CreateLuauExecutionTaskParams { + api_key: self.api_key.clone(), + universe_id: self.universe_id, + place_id: self.place_id, + version_id: self.version_id.clone(), + script, + timeout, + }) + .await + } + + pub async fn get_task(&self, task_path: String) -> Result { + luau_execution::get_luau_execution_task(&GetLuauExecutionSessionTaskParams { + api_key: self.api_key.clone(), + path: task_path, + }) + .await + } + + pub async fn get_logs( + &self, + task_path: String, + view: LuauExecutionTaskLogView, + max_page_size: Option, + page_token: Option, + ) -> Result { + luau_execution::get_luau_execution_task_logs(&GetLuauExecutionSessionTaskLogsParams { + api_key: self.api_key.clone(), + path: task_path, + view, + max_page_size, + page_token, + }) + .await + } +} + impl SubscriptionClient { pub async fn get( &self, From 7878487bd79ff861e75f8f3e710ca52687b8fb16 Mon Sep 17 00:00:00 2001 From: Stephen Leitnick Date: Fri, 21 Mar 2025 15:13:17 -0400 Subject: [PATCH 3/6] Luau execution CLI stub --- README.md | 2 +- docs/cli/cli-luau-execution.md | 1 + mkdocs.yml | 11 ++++++----- src/cli/luau_execution_cli.rs | 16 ++++++++++++++++ src/cli/mod.rs | 5 +++++ 5 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 docs/cli/cli-luau-execution.md create mode 100644 src/cli/luau_execution_cli.rs diff --git a/README.md b/README.md index af24cad..31f0c3c 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Possible use-cases: | :white_check_mark: | User Notifications | | :white_check_mark: | User | | :x: | Creator Store | -| :x: | Luau Execution | +| :white_check_mark: | Luau Execution | - :white_check_mark: = Supported - :x: = Not yet supported diff --git a/docs/cli/cli-luau-execution.md b/docs/cli/cli-luau-execution.md new file mode 100644 index 0000000..4640904 --- /dev/null +++ b/docs/cli/cli-luau-execution.md @@ -0,0 +1 @@ +# TODO diff --git a/mkdocs.yml b/mkdocs.yml index c9de1a0..1b2c5b0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -8,16 +8,17 @@ nav: - Home: index.md - CLI: - Install: cli/cli-install.md - - Assets: cli/cli-assets.md - API Key: cli/cli-api-key.md - - Experience: cli/cli-experience.md - - Messaging: cli/cli-messaging.md + - Assets: cli/cli-assets.md - DataStore: cli/cli-datastore.md - - OrderedDataStore: cli/cli-ordered-datastore.md + - Experience: cli/cli-experience.md - Group: cli/cli-group.md - - Subscription: cli/cli-subscription.md + - Luau Execution: cli/cli-luau-execution.md + - Messaging: cli/cli-messaging.md - Notification: cli/cli-notification.md + - OrderedDataStore: cli/cli-ordered-datastore.md - Place: cli/cli-place.md + - Subscription: cli/cli-subscription.md - Universe: cli/cli-universe.md - User: cli/cli-user.md - Rust Lib: diff --git a/src/cli/luau_execution_cli.rs b/src/cli/luau_execution_cli.rs new file mode 100644 index 0000000..a66167a --- /dev/null +++ b/src/cli/luau_execution_cli.rs @@ -0,0 +1,16 @@ +use clap::{Args, Subcommand}; + +#[derive(Debug, Subcommand)] +pub enum LuauExecutionCommands {} + +#[derive(Debug, Args)] +pub struct Luau { + #[clap(subcommand)] + command: LuauExecutionCommands, +} + +impl Luau { + pub async fn run(self) -> anyhow::Result> { + match self.command {} + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 1c06e27..2ecaab5 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -2,6 +2,7 @@ mod assets_cli; mod datastore_cli; mod experience_cli; mod group_cli; +mod luau_execution_cli; mod messaging_cli; mod notification_cli; mod ordered_datastore_cli; @@ -11,6 +12,7 @@ mod universe_cli; mod user_cli; use clap::{Parser, Subcommand}; +use luau_execution_cli::Luau; use universe_cli::Universe; use user_cli::User; @@ -47,6 +49,8 @@ pub enum Command { /// Access the Roblox Group API Group(Group), + Luau(Luau), + /// Access the Roblox Subscription API Subscription(Subscription), @@ -72,6 +76,7 @@ impl Cli { Command::Datastore(command) => command.run().await, Command::OrderedDatastore(command) => command.run().await, Command::Group(command) => command.run().await, + Command::Luau(command) => command.run().await, Command::Subscription(command) => command.run().await, Command::Notification(command) => command.run().await, Command::Place(command) => command.run().await, From fce95a6bc0a9e2adc5749e4af8a5d8bffd7fac3d Mon Sep 17 00:00:00 2001 From: Stephen Leitnick Date: Sat, 22 Mar 2025 18:11:27 -0400 Subject: [PATCH 4/6] Luau execution CLI --- src/cli/luau_execution_cli.rs | 225 +++++++++++++++++++++++++++++++++- src/rbx/v2/luau_execution.rs | 60 +++++++-- src/rbx/v2/mod.rs | 35 +++++- 3 files changed, 303 insertions(+), 17 deletions(-) diff --git a/src/cli/luau_execution_cli.rs b/src/cli/luau_execution_cli.rs index a66167a..f8d5bdb 100644 --- a/src/cli/luau_execution_cli.rs +++ b/src/cli/luau_execution_cli.rs @@ -1,7 +1,121 @@ use clap::{Args, Subcommand}; +use rbxcloud::rbx::{ + types::{PlaceId, UniverseId}, + v2::{luau_execution::LuauExecutionTaskLogView, Client}, +}; +use tokio::fs; #[derive(Debug, Subcommand)] -pub enum LuauExecutionCommands {} +pub enum LuauExecutionCommands { + /// Executes Luau code on Roblox + Execute { + /// Universe ID of the experience + #[clap(short, long, value_parser)] + universe_id: u64, + + /// Place ID of the experience + #[clap(short = 'i', long, value_parser)] + place_id: u64, + + /// Version ID of the experience + #[clap(short = 'r', long, value_parser)] + version_id: Option, + + /// Script source code + #[clap(short, long, value_parser)] + script: Option, + + /// Script source code file + #[clap(short, long, value_parser)] + filepath: Option, + + /// Execution timeout + #[clap(short, long, value_parser)] + timeout: 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, + }, + + /// Gets information on a previously executed task + GetTask { + /// Universe ID of the experience + #[clap(short, long, value_parser)] + universe_id: u64, + + /// Place ID of the experience + #[clap(short = 'i', long, value_parser)] + place_id: u64, + + /// Version ID of the experience + #[clap(short = 'r', long, value_parser)] + version_id: Option, + + /// Luau execution session ID + #[clap(short, long, value_parser)] + session_id: String, + + /// Luau execution task ID + #[clap(short, long, value_parser)] + task_id: String, + + /// 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, + }, + + /// Retrieves logs on a previously executed task + GetLogs { + /// Universe ID of the experience + #[clap(short, long, value_parser)] + universe_id: u64, + + /// Place ID of the experience + #[clap(short = 'i', long, value_parser)] + place_id: u64, + + /// Version ID of the experience + #[clap(short = 'r', long, value_parser)] + version_id: Option, + + /// Luau execution session ID + #[clap(short, long, value_parser)] + session_id: String, + + /// Luau execution task ID + #[clap(short, long, value_parser)] + task_id: String, + + /// Max page size + #[clap(short, long, value_parser)] + max_page_size: Option, + + /// Next page token + #[clap(short = 'n', long, value_parser)] + page_token: Option, + + /// Log view type + #[clap(short = 'w', 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 Luau { @@ -11,6 +125,113 @@ pub struct Luau { impl Luau { pub async fn run(self) -> anyhow::Result> { - match self.command {} + match self.command { + LuauExecutionCommands::Execute { + universe_id, + place_id, + version_id, + script, + filepath, + timeout, + pretty, + api_key, + } => { + let client = Client::new(&api_key); + + let luau = client.luau(UniverseId(universe_id), PlaceId(place_id), version_id); + + let mut script_source: Option = None; + if script.is_some() { + script_source = script; + } + + if script_source.is_none() { + if let Some(path) = filepath { + let src_bytes = fs::read(path).await?; + script_source = Some(String::from_utf8(src_bytes)?); + } + } + + let src = script_source.expect("script or filepath must be set"); + + let res = luau.create_task(src, timeout).await; + match res { + Ok(data) => { + let r = if pretty { + serde_json::to_string_pretty(&data)? + } else { + serde_json::to_string(&data)? + }; + Ok(Some(r)) + } + Err(err) => Err(anyhow::anyhow!(err)), + } + } + + LuauExecutionCommands::GetTask { + universe_id, + place_id, + version_id, + session_id, + task_id, + pretty, + api_key, + } => { + let client = Client::new(&api_key); + + let luau = client.luau(UniverseId(universe_id), PlaceId(place_id), version_id); + + let res = luau.get_task(session_id, task_id).await; + match res { + Ok(data) => { + let r = if pretty { + serde_json::to_string_pretty(&data)? + } else { + serde_json::to_string(&data)? + }; + Ok(Some(r)) + } + Err(err) => Err(anyhow::anyhow!(err)), + } + } + + LuauExecutionCommands::GetLogs { + universe_id, + place_id, + version_id, + session_id, + task_id, + max_page_size, + page_token, + view, + pretty, + api_key, + } => { + let client = Client::new(&api_key); + + let luau = client.luau(UniverseId(universe_id), PlaceId(place_id), version_id); + + let res = luau + .get_logs( + session_id, + task_id, + view.unwrap_or(LuauExecutionTaskLogView::Flat), + max_page_size, + page_token, + ) + .await; + match res { + Ok(data) => { + let r = if pretty { + serde_json::to_string_pretty(&data)? + } else { + serde_json::to_string(&data)? + }; + Ok(Some(r)) + } + Err(err) => Err(anyhow::anyhow!(err)), + } + } + } } } diff --git a/src/rbx/v2/luau_execution.rs b/src/rbx/v2/luau_execution.rs index 9498e19..6fedceb 100644 --- a/src/rbx/v2/luau_execution.rs +++ b/src/rbx/v2/luau_execution.rs @@ -30,21 +30,29 @@ pub struct NewLuauExecutionSessionTask { #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct GetLuauExecutionSessionTaskParams { - pub path: String, pub api_key: String, + pub universe_id: UniverseId, + pub place_id: PlaceId, + pub version_id: Option, + pub session_id: String, + pub task_id: String, } #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct GetLuauExecutionSessionTaskLogsParams { - pub path: String, pub api_key: String, + pub universe_id: UniverseId, + pub place_id: PlaceId, + pub version_id: Option, + pub session_id: String, + pub task_id: String, pub max_page_size: Option, pub page_token: Option, pub view: LuauExecutionTaskLogView, } -#[derive(Deserialize, Serialize, Debug)] +#[derive(Debug, Clone, Copy, clap::ValueEnum, Deserialize, Serialize)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum LuauExecutionTaskLogView { Flat, @@ -106,6 +114,7 @@ pub enum LuauExecutionState { #[serde(rename_all = "camelCase")] struct LuauExecutionInput { pub script: String, + #[serde(skip_serializing_if = "Option::is_none")] pub timeout: Option, } @@ -139,6 +148,7 @@ pub async fn create_luau_execution_task( let res = client .post(url) .header("x-api-key", ¶ms.api_key) + .header("Content-Type", "application/json") .body(req_body) .send() .await?; @@ -159,10 +169,24 @@ pub async fn get_luau_execution_task( ) -> Result { let client = reqwest::Client::new(); - let url = format!( - "https://apis.roblox.com/cloud/v2/{path}", - path = ¶ms.path - ); + let url = if let Some(version_id) = ¶ms.version_id { + format!( + "https://apis.roblox.com/cloud/v2/universes/{universeId}/places/{placeId}/versions/{versionId}/luau-execution-sessions/{sessionId}/tasks/{taskId}", + universeId = ¶ms.universe_id, + placeId = ¶ms.place_id, + versionId = version_id, + sessionId = ¶ms.session_id, + taskId = ¶ms.task_id, + ) + } else { + format!( + "https://apis.roblox.com/cloud/v2/universes/{universeId}/places/{placeId}/luau-execution-sessions/{sessionId}/tasks/{taskId}", + universeId = ¶ms.universe_id, + placeId = ¶ms.place_id, + sessionId = ¶ms.session_id, + taskId = ¶ms.task_id, + ) + }; let res = client .get(url) @@ -186,10 +210,24 @@ pub async fn get_luau_execution_task_logs( ) -> Result { let client = reqwest::Client::new(); - let url = format!( - "https://apis.roblox.com/cloud/v2/{path}", - path = ¶ms.path - ); + let url = if let Some(version_id) = ¶ms.version_id { + format!( + "https://apis.roblox.com/cloud/v2/universes/{universeId}/places/{placeId}/versions/{versionId}/luau-execution-sessions/{sessionId}/tasks/{taskId}/logs", + universeId = ¶ms.universe_id, + placeId = ¶ms.place_id, + versionId = version_id, + sessionId = ¶ms.session_id, + taskId = ¶ms.task_id, + ) + } else { + format!( + "https://apis.roblox.com/cloud/v2/universes/{universeId}/places/{placeId}/luau-execution-sessions/{sessionId}/tasks/{taskId}/logs", + universeId = ¶ms.universe_id, + placeId = ¶ms.place_id, + sessionId = ¶ms.session_id, + taskId = ¶ms.task_id, + ) + }; let res = client .get(url) diff --git a/src/rbx/v2/mod.rs b/src/rbx/v2/mod.rs index fb843c4..4ace408 100644 --- a/src/rbx/v2/mod.rs +++ b/src/rbx/v2/mod.rs @@ -153,24 +153,37 @@ impl LuauExecutionClient { .await } - pub async fn get_task(&self, task_path: String) -> Result { + pub async fn get_task( + &self, + session_id: String, + task_id: String, + ) -> Result { luau_execution::get_luau_execution_task(&GetLuauExecutionSessionTaskParams { api_key: self.api_key.clone(), - path: task_path, + universe_id: self.universe_id, + place_id: self.place_id, + version_id: self.version_id.clone(), + session_id, + task_id, }) .await } pub async fn get_logs( &self, - task_path: String, + session_id: String, + task_id: String, view: LuauExecutionTaskLogView, max_page_size: Option, page_token: Option, ) -> Result { luau_execution::get_luau_execution_task_logs(&GetLuauExecutionSessionTaskLogsParams { api_key: self.api_key.clone(), - path: task_path, + universe_id: self.universe_id, + place_id: self.place_id, + version_id: self.version_id.clone(), + session_id, + task_id, view, max_page_size, page_token, @@ -312,6 +325,20 @@ impl Client { } } + pub fn luau( + &self, + universe_id: UniverseId, + place_id: PlaceId, + version_id: Option, + ) -> LuauExecutionClient { + LuauExecutionClient { + api_key: self.api_key.clone(), + universe_id, + place_id, + version_id, + } + } + pub fn subscription(&self) -> SubscriptionClient { SubscriptionClient { api_key: self.api_key.clone(), From 2fea8d9e19526bc415b447c03563c9cb5b5a49b0 Mon Sep 17 00:00:00 2001 From: Stephen Leitnick Date: Sat, 22 Mar 2025 18:16:43 -0400 Subject: [PATCH 5/6] Docs --- docs/cli/cli-luau-execution.md | 55 +++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/docs/cli/cli-luau-execution.md b/docs/cli/cli-luau-execution.md index 4640904..48c926d 100644 --- a/docs/cli/cli-luau-execution.md +++ b/docs/cli/cli-luau-execution.md @@ -1 +1,54 @@ -# TODO +# Luau Execution API + +# Execute Task +Executes Luau code on Roblox. +``` +Usage: rbxcloud luau execute [OPTIONS] --universe-id --place-id --api-key + +Options: + -u, --universe-id Universe ID of the experience + -i, --place-id Place ID of the experience + -r, --version-id Version ID of the experience + -s, --script