From e40041a894676077988153cda95074892b422b2c Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Tue, 8 Apr 2025 16:07:14 -0700
Subject: [PATCH 1/8] rbx_asset: change api for asset location again

---
 rbx_asset/src/cloud.rs | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/rbx_asset/src/cloud.rs b/rbx_asset/src/cloud.rs
index f65c7aa..0016b97 100644
--- a/rbx_asset/src/cloud.rs
+++ b/rbx_asset/src/cloud.rs
@@ -178,22 +178,28 @@ impl std::fmt::Display for GetError{
 }
 impl std::error::Error for GetError{}
 
+#[derive(Debug,serde::Deserialize,serde::Serialize)]
+pub struct AssetLocation(
+	// the location is private so users cannot mutate it
+	String
+);
+impl AssetLocation{
+	pub fn location(&self)->&str{
+		let Self(location)=self;
+		location
+	}
+}
+
 #[derive(Debug,serde::Deserialize)]
 #[allow(nonstandard_style,dead_code)]
-pub struct AssetLocation{
-	// this field is private so users cannot mutate it
-	location:String,
+pub struct AssetLocationInfo{
+	pub location:Option<AssetLocation>,
 	pub requestId:String,
 	pub IsHashDynamic:bool,
 	pub IsCopyrightProtected:bool,
 	pub isArchived:bool,
 	pub assetTypeId:u32,
 }
-impl AssetLocation{
-	pub fn location(&self)->&str{
-		&self.location
-	}
-}
 
 pub struct AssetVersionsRequest{
 	pub asset_id:u64,
@@ -424,7 +430,7 @@ impl Context{
 		).await.map_err(GetError::Response)?
 		.json::<AssetResponse>().await.map_err(GetError::Reqwest)
 	}
-	pub async fn get_asset_location(&self,config:GetAssetLatestRequest)->Result<AssetLocation,GetError>{
+	pub async fn get_asset_location(&self,config:GetAssetLatestRequest)->Result<AssetLocationInfo,GetError>{
 		let raw_url=format!("https://apis.roblox.com/asset-delivery-api/v1/assetId/{}",config.asset_id);
 		let url=reqwest::Url::parse(raw_url.as_str()).map_err(GetError::ParseError)?;
 
@@ -433,7 +439,7 @@ impl Context{
 		).await.map_err(GetError::Response)?
 		.json().await.map_err(GetError::Reqwest)
 	}
-	pub async fn get_asset_version_location(&self,config:GetAssetVersionRequest)->Result<AssetLocation,GetError>{
+	pub async fn get_asset_version_location(&self,config:GetAssetVersionRequest)->Result<AssetLocationInfo,GetError>{
 		let raw_url=format!("https://apis.roblox.com/asset-delivery-api/v1/assetId/{}/version/{}",config.asset_id,config.version);
 		let url=reqwest::Url::parse(raw_url.as_str()).map_err(GetError::ParseError)?;
 
@@ -443,7 +449,7 @@ impl Context{
 		.json().await.map_err(GetError::Reqwest)
 	}
 	pub async fn get_asset(&self,config:&AssetLocation)->Result<Vec<u8>,GetError>{
-		let url=reqwest::Url::parse(config.location.as_str()).map_err(GetError::ParseError)?;
+		let url=reqwest::Url::parse(config.location()).map_err(GetError::ParseError)?;
 
 		let body=crate::response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?

From df2a5bb9ce49c78d9fb5ad48ebeac425266ffc1a Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Tue, 8 Apr 2025 16:07:33 -0700
Subject: [PATCH 2/8] rbx_asset: v0.4.3 optional AssetLocation

---
 Cargo.lock           | 2 +-
 rbx_asset/Cargo.toml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 3f60a23..a09533c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1293,7 +1293,7 @@ dependencies = [
 
 [[package]]
 name = "rbx_asset"
-version = "0.4.2"
+version = "0.4.3"
 dependencies = [
  "chrono",
  "flate2",
diff --git a/rbx_asset/Cargo.toml b/rbx_asset/Cargo.toml
index e652476..27c955b 100644
--- a/rbx_asset/Cargo.toml
+++ b/rbx_asset/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "rbx_asset"
-version = "0.4.2"
+version = "0.4.3"
 edition = "2021"
 publish = ["strafesnet"]
 repository = "https://git.itzana.me/StrafesNET/asset-tool"

From 50145460b9bb9ec8e0cf7a1dc0c0d48cdb9f7efd Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 10 Apr 2025 00:24:55 -0700
Subject: [PATCH 3/8] rbx_asset: simplify gzip logic

---
 Cargo.lock              |  1 +
 rbx_asset/Cargo.toml    |  1 +
 rbx_asset/src/cloud.rs  |  8 ++------
 rbx_asset/src/cookie.rs | 15 ++++-----------
 rbx_asset/src/lib.rs    | 25 +++++++++----------------
 5 files changed, 17 insertions(+), 33 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index a09533c..c020c03 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1295,6 +1295,7 @@ dependencies = [
 name = "rbx_asset"
 version = "0.4.3"
 dependencies = [
+ "bytes",
  "chrono",
  "flate2",
  "reqwest",
diff --git a/rbx_asset/Cargo.toml b/rbx_asset/Cargo.toml
index 27c955b..2b0ad78 100644
--- a/rbx_asset/Cargo.toml
+++ b/rbx_asset/Cargo.toml
@@ -11,6 +11,7 @@ authors = ["Rhys Lloyd <krakow20@gmail.com>"]
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+bytes = "1.10.1"
 chrono = { version = "0.4.38", features = ["serde"] }
 flate2 = "1.0.29"
 reqwest = { version = "0.12.4", features = ["json","multipart"] }
diff --git a/rbx_asset/src/cloud.rs b/rbx_asset/src/cloud.rs
index 0016b97..fae4f61 100644
--- a/rbx_asset/src/cloud.rs
+++ b/rbx_asset/src/cloud.rs
@@ -1,4 +1,4 @@
-use crate::{ResponseError,ReaderType,maybe_gzip_decode,read_readable};
+use crate::{ResponseError,maybe_gzip_decode};
 
 #[derive(Debug,serde::Deserialize,serde::Serialize)]
 #[allow(nonstandard_style,dead_code)]
@@ -456,11 +456,7 @@ impl Context{
 		).await.map_err(GetError::Response)?
 		.bytes().await.map_err(GetError::Reqwest)?;
 
-		match maybe_gzip_decode(std::io::Cursor::new(body)){
-			Ok(ReaderType::GZip(readable))=>read_readable(readable),
-			Ok(ReaderType::Raw(readable))=>read_readable(readable),
-			Err(e)=>Err(e),
-		}.map_err(GetError::IO)
+		maybe_gzip_decode(body).map_err(GetError::IO)
 	}
 	pub async fn get_asset_versions(&self,config:AssetVersionsRequest)->Result<AssetVersionsResponse,AssetVersionsError>{
 		let raw_url=format!("https://apis.roblox.com/assets/v1/assets/{}/versions",config.asset_id);
diff --git a/rbx_asset/src/cookie.rs b/rbx_asset/src/cookie.rs
index 7ad53f2..5ba4532 100644
--- a/rbx_asset/src/cookie.rs
+++ b/rbx_asset/src/cookie.rs
@@ -1,4 +1,4 @@
-use crate::{ResponseError,ReaderType,maybe_gzip_decode,read_readable};
+use crate::{ResponseError,maybe_gzip_decode};
 
 #[derive(Debug)]
 pub enum PostError{
@@ -464,11 +464,8 @@ impl Context{
 		).await.map_err(GetError::Response)?
 		.bytes().await.map_err(GetError::Reqwest)?;
 
-		match maybe_gzip_decode(std::io::Cursor::new(body)){
-			Ok(ReaderType::GZip(readable))=>read_readable(readable),
-			Ok(ReaderType::Raw(readable))=>read_readable(readable),
-			Err(e)=>Err(e),
-		}.map_err(GetError::IO)
+
+		maybe_gzip_decode(body).map_err(GetError::IO)
 	}
 	pub async fn get_asset_v2(&self,config:GetAssetRequest)->Result<GetAssetV2,GetAssetV2Error>{
 		let mut url=reqwest::Url::parse("https://assetdelivery.roblox.com/v2/asset").map_err(GetAssetV2Error::ParseError)?;
@@ -508,11 +505,7 @@ impl Context{
 		).await.map_err(GetError::Response)?
 		.bytes().await.map_err(GetError::Reqwest)?;
 
-		match maybe_gzip_decode(std::io::Cursor::new(body)){
-			Ok(ReaderType::GZip(readable))=>read_readable(readable),
-			Ok(ReaderType::Raw(readable))=>read_readable(readable),
-			Err(e)=>Err(e),
-		}.map_err(GetError::IO)
+		maybe_gzip_decode(body).map_err(GetError::IO)
 	}
 	pub async fn get_asset_details(&self,config:GetAssetDetailsRequest)->Result<AssetDetails,GetError>{
 		let url=reqwest::Url::parse(format!("https://economy.roblox.com/v2/assets/{}/details",config.asset_id).as_str()).map_err(GetError::ParseError)?;
diff --git a/rbx_asset/src/lib.rs b/rbx_asset/src/lib.rs
index c41ff74..0c6f8fb 100644
--- a/rbx_asset/src/lib.rs
+++ b/rbx_asset/src/lib.rs
@@ -36,21 +36,14 @@ pub(crate) async fn response_ok(response:reqwest::Response)->Result<reqwest::Res
 	}
 }
 
-//idk how to do this better
-pub(crate) enum ReaderType<R:std::io::Read>{
-	GZip(flate2::read::GzDecoder<std::io::BufReader<R>>),
-	Raw(std::io::BufReader<R>),
-}
-pub(crate) fn maybe_gzip_decode<R:std::io::Read>(input:R)->std::io::Result<ReaderType<R>>{
-	let mut buf=std::io::BufReader::new(input);
-	let peek=std::io::BufRead::fill_buf(&mut buf)?;
-	match &peek[0..2]{
-		b"\x1f\x8b"=>Ok(ReaderType::GZip(flate2::read::GzDecoder::new(buf))),
-		_=>Ok(ReaderType::Raw(buf)),
+pub(crate) fn maybe_gzip_decode(data:bytes::Bytes)->std::io::Result<Vec<u8>>{
+	match data.get(0..2){
+		Some(b"\x1f\x8b")=>{
+			use std::io::Read;
+			let mut buf=Vec::new();
+			flate2::read::GzDecoder::new(std::io::Cursor::new(data)).read_to_end(&mut buf)?;
+			Ok(buf)
+		},
+		_=>Ok(data.to_vec()),
 	}
 }
-pub(crate) fn read_readable(mut readable:impl std::io::Read)->std::io::Result<Vec<u8>>{
-	let mut contents=Vec::new();
-	readable.read_to_end(&mut contents)?;
-	Ok(contents)
-}

From d77312309f53966ff8c90d9a460354db51e915ce Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 10 Apr 2025 15:26:02 -0700
Subject: [PATCH 4/8] rbx_asset: helpers for integers within a string

---
 rbx_asset/src/cloud.rs | 14 ++++++++++----
 rbx_asset/src/lib.rs   |  1 +
 rbx_asset/src/util.rs  | 21 +++++++++++++++++++++
 src/main.rs            | 10 +++++-----
 4 files changed, 37 insertions(+), 9 deletions(-)
 create mode 100644 rbx_asset/src/util.rs

diff --git a/rbx_asset/src/cloud.rs b/rbx_asset/src/cloud.rs
index fae4f61..bdc5fd1 100644
--- a/rbx_asset/src/cloud.rs
+++ b/rbx_asset/src/cloud.rs
@@ -1,3 +1,4 @@
+use crate::util::{serialize_u64,deserialize_u64};
 use crate::{ResponseError,maybe_gzip_decode};
 
 #[derive(Debug,serde::Deserialize,serde::Serialize)]
@@ -65,8 +66,8 @@ pub struct UpdateAssetRequest{
 #[derive(Clone,Debug,serde::Deserialize,serde::Serialize)]
 #[allow(nonstandard_style,dead_code)]
 pub enum Creator{
-	userId(String),//u64 string
-	groupId(String),//u64 string
+	userId(#[serde(deserialize_with="deserialize_u64",serialize_with="serialize_u64")]u64),
+	groupId(#[serde(deserialize_with="deserialize_u64",serialize_with="serialize_u64")]u64),
 }
 #[derive(Debug,serde::Deserialize,serde::Serialize)]
 #[allow(nonstandard_style,dead_code)]
@@ -146,14 +147,19 @@ pub struct GetAssetLatestRequest{
 #[derive(Debug,serde::Deserialize,serde::Serialize)]
 #[allow(nonstandard_style,dead_code)]
 pub struct AssetResponse{
-	pub assetId:String,//u64 wrapped in quotes wohoo!!
+	//u64 wrapped in quotes wohoo!!
+	#[serde(deserialize_with="deserialize_u64")]
+	#[serde(serialize_with="serialize_u64")]
+	pub assetId:u64,
 	pub assetType:AssetType,
 	pub creationContext:CreationContext,
 	pub description:Option<String>,
 	pub displayName:String,
 	pub path:String,
 	pub revisionCreateTime:chrono::DateTime<chrono::Utc>,
-	pub revisionId:String,//u64
+	#[serde(deserialize_with="deserialize_u64")]
+	#[serde(serialize_with="serialize_u64")]
+	pub revisionId:u64,
 	pub moderationResult:ModerationResult,
 	pub icon:Option<String>,
 	#[serde(default)]
diff --git a/rbx_asset/src/lib.rs b/rbx_asset/src/lib.rs
index 0c6f8fb..7a5274a 100644
--- a/rbx_asset/src/lib.rs
+++ b/rbx_asset/src/lib.rs
@@ -1,5 +1,6 @@
 pub mod cloud;
 pub mod cookie;
+mod util;
 
 #[allow(dead_code)]
 #[derive(Debug)]
diff --git a/rbx_asset/src/util.rs b/rbx_asset/src/util.rs
new file mode 100644
index 0000000..24ae3d5
--- /dev/null
+++ b/rbx_asset/src/util.rs
@@ -0,0 +1,21 @@
+use serde::de::{Error,Unexpected};
+use serde::{Deserializer,Serializer};
+
+struct U64StringVisitor;
+impl serde::de::Visitor<'_> for U64StringVisitor{
+	type Value=u64;
+	fn expecting(&self,formatter:&mut std::fmt::Formatter)->std::fmt::Result{
+		write!(formatter,"string value with int")
+	}
+	fn visit_str<E:Error>(self,v:&str)->Result<Self::Value,E>{
+		v.parse().map_err(|_|E::invalid_value(Unexpected::Str(v),&"u64"))
+	}
+}
+
+pub(crate) fn deserialize_u64<'de,D:Deserializer<'de>>(deserializer:D)->Result<u64,D::Error>{
+	deserializer.deserialize_any(U64StringVisitor)
+}
+
+pub(crate) fn serialize_u64<S:Serializer>(v:&u64,serializer:S)->Result<S::Ok,S::Error>{
+	serializer.serialize_str(v.to_string().as_str())
+}
diff --git a/src/main.rs b/src/main.rs
index ba89009..b30aa28 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -563,8 +563,8 @@ async fn main()->AResult<()>{
 				subcommand.api_key_file,
 			).await?,
 			creator:match (subcommand.creator_user_id,subcommand.creator_group_id){
-				(Some(user_id),None)=>rbx_asset::cloud::Creator::userId(user_id.to_string()),
-				(None,Some(group_id))=>rbx_asset::cloud::Creator::groupId(group_id.to_string()),
+				(Some(user_id),None)=>rbx_asset::cloud::Creator::userId(user_id),
+				(None,Some(group_id))=>rbx_asset::cloud::Creator::groupId(group_id),
 				other=>Err(anyhow!("Invalid creator {other:?}"))?,
 			},
 			input_file:subcommand.input_file,
@@ -585,8 +585,8 @@ async fn main()->AResult<()>{
 				subcommand.cookie_file,
 			).await?,
 			creator:match (subcommand.creator_user_id,subcommand.creator_group_id){
-				(Some(user_id),None)=>rbx_asset::cloud::Creator::userId(user_id.to_string()),
-				(None,Some(group_id))=>rbx_asset::cloud::Creator::groupId(group_id.to_string()),
+				(Some(user_id),None)=>rbx_asset::cloud::Creator::userId(user_id),
+				(None,Some(group_id))=>rbx_asset::cloud::Creator::groupId(group_id),
 				other=>Err(anyhow!("Invalid creator {other:?}"))?,
 			},
 			description:subcommand.description.unwrap_or_else(||String::with_capacity(0)),
@@ -904,7 +904,7 @@ async fn create_asset_medias(config:CreateAssetMediasConfig)->AResult<()>{
 		async move{
 			let asset_response=asset_response_result.map_err(DownloadDecalError::PollOperation)?;
 			let file=cookie_context.get_asset(rbx_asset::cookie::GetAssetRequest{
-				asset_id:asset_response.assetId.parse().map_err(DownloadDecalError::ParseInt)?,
+				asset_id:asset_response.assetId,
 				version:None,
 			}).await.map_err(DownloadDecalError::Get)?;
 			let dom=load_dom(std::io::Cursor::new(file)).map_err(DownloadDecalError::LoadDom)?;

From 041cc75015b7af11712931c0ddac920a2e162b28 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 10 Apr 2025 17:24:44 -0700
Subject: [PATCH 5/8] rbx_asset: move code into util, types

---
 rbx_asset/src/cloud.rs  | 26 +++++++++++-----------
 rbx_asset/src/cookie.rs | 21 +++++++++---------
 rbx_asset/src/lib.rs    | 48 +----------------------------------------
 rbx_asset/src/types.rs  | 18 ++++++++++++++++
 rbx_asset/src/util.rs   | 31 ++++++++++++++++++++++++++
 5 files changed, 74 insertions(+), 70 deletions(-)
 create mode 100644 rbx_asset/src/types.rs

diff --git a/rbx_asset/src/cloud.rs b/rbx_asset/src/cloud.rs
index bdc5fd1..93085d6 100644
--- a/rbx_asset/src/cloud.rs
+++ b/rbx_asset/src/cloud.rs
@@ -1,5 +1,5 @@
-use crate::util::{serialize_u64,deserialize_u64};
-use crate::{ResponseError,maybe_gzip_decode};
+use crate::util::{serialize_u64,deserialize_u64,response_ok,maybe_gzip_decode};
+use crate::types::{ResponseError};
 
 #[derive(Debug,serde::Deserialize,serde::Serialize)]
 #[allow(nonstandard_style,dead_code)]
@@ -381,7 +381,7 @@ impl Context{
 		.text("request",request_config)
 		.part("fileContent",part);
 
-		let operation=crate::response_ok(
+		let operation=response_ok(
 			self.post_form(url,form).await.map_err(CreateError::Reqwest)?
 		).await.map_err(CreateError::Response)?
 		.json::<RobloxOperation>().await.map_err(CreateError::Reqwest)?;
@@ -400,7 +400,7 @@ impl Context{
 		.text("request",request_config)
 		.part("fileContent",reqwest::multipart::Part::bytes(body));
 
-		let operation=crate::response_ok(
+		let operation=response_ok(
 			self.patch_form(url,form).await.map_err(UpdateError::Reqwest)?
 		).await.map_err(UpdateError::Response)?
 		.json::<RobloxOperation>().await.map_err(UpdateError::Reqwest)?;
@@ -413,7 +413,7 @@ impl Context{
 		let raw_url=format!("https://apis.roblox.com/assets/v1/operations/{}",config.operation_id);
 		let url=reqwest::Url::parse(raw_url.as_str()).map_err(GetError::ParseError)?;
 
-		crate::response_ok(
+		response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?
 		).await.map_err(GetError::Response)?
 		.json::<RobloxOperation>().await.map_err(GetError::Reqwest)
@@ -422,7 +422,7 @@ impl Context{
 		let raw_url=format!("https://apis.roblox.com/assets/v1/assets/{}",config.asset_id);
 		let url=reqwest::Url::parse(raw_url.as_str()).map_err(GetError::ParseError)?;
 
-		crate::response_ok(
+		response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?
 		).await.map_err(GetError::Response)?
 		.json::<AssetResponse>().await.map_err(GetError::Reqwest)
@@ -431,7 +431,7 @@ impl Context{
 		let raw_url=format!("https://apis.roblox.com/assets/v1/assets/{}/versions/{}",config.asset_id,config.version);
 		let url=reqwest::Url::parse(raw_url.as_str()).map_err(GetError::ParseError)?;
 
-		crate::response_ok(
+		response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?
 		).await.map_err(GetError::Response)?
 		.json::<AssetResponse>().await.map_err(GetError::Reqwest)
@@ -440,7 +440,7 @@ impl Context{
 		let raw_url=format!("https://apis.roblox.com/asset-delivery-api/v1/assetId/{}",config.asset_id);
 		let url=reqwest::Url::parse(raw_url.as_str()).map_err(GetError::ParseError)?;
 
-		crate::response_ok(
+		response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?
 		).await.map_err(GetError::Response)?
 		.json().await.map_err(GetError::Reqwest)
@@ -449,7 +449,7 @@ impl Context{
 		let raw_url=format!("https://apis.roblox.com/asset-delivery-api/v1/assetId/{}/version/{}",config.asset_id,config.version);
 		let url=reqwest::Url::parse(raw_url.as_str()).map_err(GetError::ParseError)?;
 
-		crate::response_ok(
+		response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?
 		).await.map_err(GetError::Response)?
 		.json().await.map_err(GetError::Reqwest)
@@ -457,7 +457,7 @@ impl Context{
 	pub async fn get_asset(&self,config:&AssetLocation)->Result<Vec<u8>,GetError>{
 		let url=reqwest::Url::parse(config.location()).map_err(GetError::ParseError)?;
 
-		let body=crate::response_ok(
+		let body=response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?
 		).await.map_err(GetError::Response)?
 		.bytes().await.map_err(GetError::Reqwest)?;
@@ -468,7 +468,7 @@ impl Context{
 		let raw_url=format!("https://apis.roblox.com/assets/v1/assets/{}/versions",config.asset_id);
 		let url=reqwest::Url::parse(raw_url.as_str()).map_err(AssetVersionsError::ParseError)?;
 
-		crate::response_ok(
+		response_ok(
 			self.get(url).await.map_err(AssetVersionsError::Reqwest)?
 		).await.map_err(AssetVersionsError::Response)?
 		.json::<AssetVersionsResponse>().await.map_err(AssetVersionsError::Reqwest)
@@ -483,7 +483,7 @@ impl Context{
 			}
 		}
 
-		crate::response_ok(
+		response_ok(
 			self.get(url).await.map_err(InventoryPageError::Reqwest)?
 		).await.map_err(InventoryPageError::Response)?
 		.json::<InventoryPageResponse>().await.map_err(InventoryPageError::Reqwest)
@@ -497,7 +497,7 @@ impl Context{
 			query.append_pair("versionType","Published");
 		}
 
-		crate::response_ok(
+		response_ok(
 			self.post(url,body).await.map_err(UpdateError::Reqwest)?
 		).await.map_err(UpdateError::Response)?
 		.json::<UpdatePlaceResponse>().await.map_err(UpdateError::Reqwest)
diff --git a/rbx_asset/src/cookie.rs b/rbx_asset/src/cookie.rs
index 5ba4532..8369965 100644
--- a/rbx_asset/src/cookie.rs
+++ b/rbx_asset/src/cookie.rs
@@ -1,4 +1,5 @@
-use crate::{ResponseError,maybe_gzip_decode};
+use crate::util::{response_ok,maybe_gzip_decode};
+use crate::types::ResponseError;
 
 #[derive(Debug)]
 pub enum PostError{
@@ -371,7 +372,7 @@ impl Context{
 				query.append_pair("groupId",group_id.to_string().as_str());
 			}
 		}
-		let response=crate::response_ok(
+		let response=response_ok(
 			self.post(url,body).await.map_err(CreateError::PostError)?
 		).await.map_err(CreateError::Response)?;
 
@@ -423,7 +424,7 @@ impl Context{
 				query.append_pair("groupId",group_id.to_string().as_str());
 			}
 		}
-		let response=crate::response_ok(
+		let response=response_ok(
 			self.post(url,body).await.map_err(UploadError::PostError)?
 		).await.map_err(UploadError::Response)?;
 
@@ -459,7 +460,7 @@ impl Context{
 				query.append_pair("version",version.to_string().as_str());
 			}
 		}
-		let body=crate::response_ok(
+		let body=response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?
 		).await.map_err(GetError::Response)?
 		.bytes().await.map_err(GetError::Reqwest)?;
@@ -477,7 +478,7 @@ impl Context{
 				query.append_pair("version",version.to_string().as_str());
 			}
 		}
-		let response=crate::response_ok(
+		let response=response_ok(
 			self.get(url).await.map_err(GetAssetV2Error::Reqwest)?
 		).await.map_err(GetAssetV2Error::Response)?;
 
@@ -500,7 +501,7 @@ impl Context{
 	pub async fn get_asset_v2_download(&self,config:&GetAssetV2Location)->Result<Vec<u8>,GetError>{
 		let url=reqwest::Url::parse(config.location.as_str()).map_err(GetError::ParseError)?;
 
-		let body=crate::response_ok(
+		let body=response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?
 		).await.map_err(GetError::Response)?
 		.bytes().await.map_err(GetError::Reqwest)?;
@@ -509,7 +510,7 @@ impl Context{
 	}
 	pub async fn get_asset_details(&self,config:GetAssetDetailsRequest)->Result<AssetDetails,GetError>{
 		let url=reqwest::Url::parse(format!("https://economy.roblox.com/v2/assets/{}/details",config.asset_id).as_str()).map_err(GetError::ParseError)?;
-		crate::response_ok(
+		response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?
 		).await.map_err(GetError::Response)?
 		.json().await.map_err(GetError::Reqwest)
@@ -526,7 +527,7 @@ impl Context{
 				query.append_pair("cursor",cursor);
 			}
 		}
-		crate::response_ok(
+		response_ok(
 			self.get(url).await.map_err(PageError::Reqwest)?
 		).await.map_err(PageError::Response)?
 		.json::<AssetVersionsPageResponse>().await.map_err(PageError::Reqwest)
@@ -541,7 +542,7 @@ impl Context{
 				query.append_pair("cursor",cursor);
 			}
 		}
-		crate::response_ok(
+		response_ok(
 			self.get(url).await.map_err(PageError::Reqwest)?
 		).await.map_err(PageError::Response)?
 		.json::<CreationsPageResponse>().await.map_err(PageError::Reqwest)
@@ -555,7 +556,7 @@ impl Context{
 				query.append_pair("cursor",cursor);
 			}
 		}
-		crate::response_ok(
+		response_ok(
 			self.get(url).await.map_err(PageError::Reqwest)?
 		).await.map_err(PageError::Response)?
 		.json::<UserInventoryPageResponse>().await.map_err(PageError::Reqwest)
diff --git a/rbx_asset/src/lib.rs b/rbx_asset/src/lib.rs
index 7a5274a..a6a3487 100644
--- a/rbx_asset/src/lib.rs
+++ b/rbx_asset/src/lib.rs
@@ -1,50 +1,4 @@
 pub mod cloud;
 pub mod cookie;
+pub mod types;
 mod util;
-
-#[allow(dead_code)]
-#[derive(Debug)]
-pub struct StatusCodeWithUrlAndBody{
-	pub status_code:reqwest::StatusCode,
-	pub url:url::Url,
-	pub body:String,
-}
-#[derive(Debug)]
-pub enum ResponseError{
-	Reqwest(reqwest::Error),
-	StatusCodeWithUrlAndBody(StatusCodeWithUrlAndBody),
-}
-impl std::fmt::Display for ResponseError{
-	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-		write!(f,"{self:?}")
-	}
-}
-impl std::error::Error for ResponseError{}
-// lazy function to draw out meaningful info from http response on failure
-pub(crate) async fn response_ok(response:reqwest::Response)->Result<reqwest::Response,ResponseError>{
-	let status_code=response.status();
-	if status_code.is_success(){
-		Ok(response)
-	}else{
-		let url=response.url().to_owned();
-		let bytes=response.bytes().await.map_err(ResponseError::Reqwest)?;
-		let body=String::from_utf8_lossy(&bytes).to_string();
-		Err(ResponseError::StatusCodeWithUrlAndBody(StatusCodeWithUrlAndBody{
-			status_code,
-			url,
-			body,
-		}))
-	}
-}
-
-pub(crate) fn maybe_gzip_decode(data:bytes::Bytes)->std::io::Result<Vec<u8>>{
-	match data.get(0..2){
-		Some(b"\x1f\x8b")=>{
-			use std::io::Read;
-			let mut buf=Vec::new();
-			flate2::read::GzDecoder::new(std::io::Cursor::new(data)).read_to_end(&mut buf)?;
-			Ok(buf)
-		},
-		_=>Ok(data.to_vec()),
-	}
-}
diff --git a/rbx_asset/src/types.rs b/rbx_asset/src/types.rs
new file mode 100644
index 0000000..b9ef790
--- /dev/null
+++ b/rbx_asset/src/types.rs
@@ -0,0 +1,18 @@
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct StatusCodeWithUrlAndBody{
+	pub status_code:reqwest::StatusCode,
+	pub url:url::Url,
+	pub body:String,
+}
+#[derive(Debug)]
+pub enum ResponseError{
+	Reqwest(reqwest::Error),
+	StatusCodeWithUrlAndBody(StatusCodeWithUrlAndBody),
+}
+impl std::fmt::Display for ResponseError{
+	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+		write!(f,"{self:?}")
+	}
+}
+impl std::error::Error for ResponseError{}
diff --git a/rbx_asset/src/util.rs b/rbx_asset/src/util.rs
index 24ae3d5..5cc08b7 100644
--- a/rbx_asset/src/util.rs
+++ b/rbx_asset/src/util.rs
@@ -1,3 +1,34 @@
+use crate::types::{ResponseError,StatusCodeWithUrlAndBody};
+
+// lazy function to draw out meaningful info from http response on failure
+pub(crate) async fn response_ok(response:reqwest::Response)->Result<reqwest::Response,ResponseError>{
+	let status_code=response.status();
+	if status_code.is_success(){
+		Ok(response)
+	}else{
+		let url=response.url().to_owned();
+		let bytes=response.bytes().await.map_err(ResponseError::Reqwest)?;
+		let body=String::from_utf8_lossy(&bytes).to_string();
+		Err(ResponseError::StatusCodeWithUrlAndBody(StatusCodeWithUrlAndBody{
+			status_code,
+			url,
+			body,
+		}))
+	}
+}
+
+pub(crate) fn maybe_gzip_decode(data:bytes::Bytes)->std::io::Result<Vec<u8>>{
+	match data.get(0..2){
+		Some(b"\x1f\x8b")=>{
+			use std::io::Read;
+			let mut buf=Vec::new();
+			flate2::read::GzDecoder::new(std::io::Cursor::new(data)).read_to_end(&mut buf)?;
+			Ok(buf)
+		},
+		_=>Ok(data.to_vec()),
+	}
+}
+
 use serde::de::{Error,Unexpected};
 use serde::{Deserializer,Serializer};
 

From 31aae80cc50431d669c21df351881d442d36a18a Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 10 Apr 2025 15:55:09 -0700
Subject: [PATCH 6/8] rbx_asset: change api to save intermediate allocation

---
 rbx_asset/Cargo.toml    |  6 ++++-
 rbx_asset/src/cloud.rs  | 11 +++++----
 rbx_asset/src/cookie.rs | 19 ++++++++--------
 rbx_asset/src/types.rs  | 50 +++++++++++++++++++++++++++++++++++++++++
 rbx_asset/src/util.rs   | 12 ----------
 src/main.rs             | 26 ++++++++++-----------
 6 files changed, 82 insertions(+), 42 deletions(-)

diff --git a/rbx_asset/Cargo.toml b/rbx_asset/Cargo.toml
index 2b0ad78..0120817 100644
--- a/rbx_asset/Cargo.toml
+++ b/rbx_asset/Cargo.toml
@@ -10,10 +10,14 @@ authors = ["Rhys Lloyd <krakow20@gmail.com>"]
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
+[features]
+default = ["gzip"]
+gzip = ["dep:flate2"]
+
 [dependencies]
 bytes = "1.10.1"
 chrono = { version = "0.4.38", features = ["serde"] }
-flate2 = "1.0.29"
+flate2 = { version = "1.0.29", optional = true }
 reqwest = { version = "0.12.4", features = ["json","multipart"] }
 serde = { version = "1.0.199", features = ["derive"] }
 serde_json = "1.0.111"
diff --git a/rbx_asset/src/cloud.rs b/rbx_asset/src/cloud.rs
index 93085d6..71f4a9e 100644
--- a/rbx_asset/src/cloud.rs
+++ b/rbx_asset/src/cloud.rs
@@ -1,5 +1,5 @@
-use crate::util::{serialize_u64,deserialize_u64,response_ok,maybe_gzip_decode};
-use crate::types::{ResponseError};
+use crate::util::{serialize_u64,deserialize_u64,response_ok};
+use crate::types::{ResponseError,MaybeGzippedBytes};
 
 #[derive(Debug,serde::Deserialize,serde::Serialize)]
 #[allow(nonstandard_style,dead_code)]
@@ -175,7 +175,6 @@ pub enum GetError{
 	ParseError(url::ParseError),
 	Response(ResponseError),
 	Reqwest(reqwest::Error),
-	IO(std::io::Error)
 }
 impl std::fmt::Display for GetError{
 	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -454,15 +453,15 @@ impl Context{
 		).await.map_err(GetError::Response)?
 		.json().await.map_err(GetError::Reqwest)
 	}
-	pub async fn get_asset(&self,config:&AssetLocation)->Result<Vec<u8>,GetError>{
+	pub async fn get_asset(&self,config:&AssetLocation)->Result<MaybeGzippedBytes,GetError>{
 		let url=reqwest::Url::parse(config.location()).map_err(GetError::ParseError)?;
 
-		let body=response_ok(
+		let bytes=response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?
 		).await.map_err(GetError::Response)?
 		.bytes().await.map_err(GetError::Reqwest)?;
 
-		maybe_gzip_decode(body).map_err(GetError::IO)
+		Ok(MaybeGzippedBytes::new(bytes))
 	}
 	pub async fn get_asset_versions(&self,config:AssetVersionsRequest)->Result<AssetVersionsResponse,AssetVersionsError>{
 		let raw_url=format!("https://apis.roblox.com/assets/v1/assets/{}/versions",config.asset_id);
diff --git a/rbx_asset/src/cookie.rs b/rbx_asset/src/cookie.rs
index 8369965..efee3dc 100644
--- a/rbx_asset/src/cookie.rs
+++ b/rbx_asset/src/cookie.rs
@@ -1,5 +1,5 @@
-use crate::util::{response_ok,maybe_gzip_decode};
-use crate::types::ResponseError;
+use crate::util::response_ok;
+use crate::types::{ResponseError,MaybeGzippedBytes};
 
 #[derive(Debug)]
 pub enum PostError{
@@ -92,7 +92,6 @@ pub enum GetError{
 	ParseError(url::ParseError),
 	Response(ResponseError),
 	Reqwest(reqwest::Error),
-	IO(std::io::Error)
 }
 impl std::fmt::Display for GetError{
 	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -450,7 +449,7 @@ impl Context{
 			})
 		}
 	}
-	pub async fn get_asset(&self,config:GetAssetRequest)->Result<Vec<u8>,GetError>{
+	pub async fn get_asset(&self,config:GetAssetRequest)->Result<MaybeGzippedBytes,GetError>{
 		let mut url=reqwest::Url::parse("https://assetdelivery.roblox.com/v1/asset/").map_err(GetError::ParseError)?;
 		//url borrow scope
 		{
@@ -460,13 +459,13 @@ impl Context{
 				query.append_pair("version",version.to_string().as_str());
 			}
 		}
-		let body=response_ok(
+
+		let bytes=response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?
 		).await.map_err(GetError::Response)?
 		.bytes().await.map_err(GetError::Reqwest)?;
 
-
-		maybe_gzip_decode(body).map_err(GetError::IO)
+		Ok(MaybeGzippedBytes::new(bytes))
 	}
 	pub async fn get_asset_v2(&self,config:GetAssetRequest)->Result<GetAssetV2,GetAssetV2Error>{
 		let mut url=reqwest::Url::parse("https://assetdelivery.roblox.com/v2/asset").map_err(GetAssetV2Error::ParseError)?;
@@ -498,15 +497,15 @@ impl Context{
 			info,
 		})
 	}
-	pub async fn get_asset_v2_download(&self,config:&GetAssetV2Location)->Result<Vec<u8>,GetError>{
+	pub async fn get_asset_v2_download(&self,config:&GetAssetV2Location)->Result<MaybeGzippedBytes,GetError>{
 		let url=reqwest::Url::parse(config.location.as_str()).map_err(GetError::ParseError)?;
 
-		let body=response_ok(
+		let bytes=response_ok(
 			self.get(url).await.map_err(GetError::Reqwest)?
 		).await.map_err(GetError::Response)?
 		.bytes().await.map_err(GetError::Reqwest)?;
 
-		maybe_gzip_decode(body).map_err(GetError::IO)
+		Ok(MaybeGzippedBytes::new(bytes))
 	}
 	pub async fn get_asset_details(&self,config:GetAssetDetailsRequest)->Result<AssetDetails,GetError>{
 		let url=reqwest::Url::parse(format!("https://economy.roblox.com/v2/assets/{}/details",config.asset_id).as_str()).map_err(GetError::ParseError)?;
diff --git a/rbx_asset/src/types.rs b/rbx_asset/src/types.rs
index b9ef790..2aa64f5 100644
--- a/rbx_asset/src/types.rs
+++ b/rbx_asset/src/types.rs
@@ -16,3 +16,53 @@ impl std::fmt::Display for ResponseError{
 	}
 }
 impl std::error::Error for ResponseError{}
+
+#[cfg(feature="gzip")]
+use std::io::Cursor;
+#[cfg(feature="gzip")]
+use flate2::read::GzDecoder;
+
+/// Some bytes that might be gzipped.  Use the read_with or to_vec methods to transparently decode gzip.
+pub struct MaybeGzippedBytes{
+	bytes:bytes::Bytes,
+}
+impl MaybeGzippedBytes{
+	pub(crate) fn new(bytes:bytes::Bytes)->Self{
+		Self{bytes}
+	}
+	pub fn into_inner(self)->bytes::Bytes{
+		self.bytes
+	}
+	/// get a reference to the bytes, ignoring gzip decoding
+	pub fn as_raw_ref(&self)->&[u8]{
+		self.bytes.as_ref()
+	}
+	/// Transparently decode gzip data, if present (intermediate allocation)
+	#[cfg(feature="gzip")]
+	pub fn to_vec(&self)->std::io::Result<Vec<u8>>{
+		use std::io::Read;
+		match self.bytes.get(0..2){
+			Some(b"\x1f\x8b")=>{
+				let mut buf=Vec::new();
+				GzDecoder::new(Cursor::new(self.bytes.as_ref())).read_to_end(&mut buf)?;
+				Ok(buf)
+			},
+			_=>Ok(self.bytes.to_vec())
+		}
+	}
+	/// Read the bytes with the provided decoders.
+	/// The idea is to make a function that is generic over std::io::Read
+	/// and pass the same function to both closures.
+	/// This two closure hack must be done because of the different concrete types.
+	#[cfg(feature="gzip")]
+	pub fn read_with<'a,ReadGzip,ReadRaw,T>(&'a self,read_gzip:ReadGzip,read_raw:ReadRaw)->T
+		where
+			ReadGzip:Fn(GzDecoder<Cursor<&'a [u8]>>)->T,
+			ReadRaw:Fn(Cursor<&'a [u8]>)->T,
+	{
+		match self.bytes.get(0..2){
+			Some(b"\x1f\x8b")=>read_gzip(GzDecoder::new(Cursor::new(self.bytes.as_ref()))),
+			_=>read_raw(Cursor::new(self.bytes.as_ref()))
+		}
+	}
+}
diff --git a/rbx_asset/src/util.rs b/rbx_asset/src/util.rs
index 5cc08b7..9f8a785 100644
--- a/rbx_asset/src/util.rs
+++ b/rbx_asset/src/util.rs
@@ -17,18 +17,6 @@ pub(crate) async fn response_ok(response:reqwest::Response)->Result<reqwest::Res
 	}
 }
 
-pub(crate) fn maybe_gzip_decode(data:bytes::Bytes)->std::io::Result<Vec<u8>>{
-	match data.get(0..2){
-		Some(b"\x1f\x8b")=>{
-			use std::io::Read;
-			let mut buf=Vec::new();
-			flate2::read::GzDecoder::new(std::io::Cursor::new(data)).read_to_end(&mut buf)?;
-			Ok(buf)
-		},
-		_=>Ok(data.to_vec()),
-	}
-}
-
 use serde::de::{Error,Unexpected};
 use serde::{Deserializer,Serializer};
 
diff --git a/src/main.rs b/src/main.rs
index b30aa28..e8703bf 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -903,11 +903,11 @@ async fn create_asset_medias(config:CreateAssetMediasConfig)->AResult<()>{
 		async move{(path,
 		async move{
 			let asset_response=asset_response_result.map_err(DownloadDecalError::PollOperation)?;
-			let file=cookie_context.get_asset(rbx_asset::cookie::GetAssetRequest{
+			let maybe_gzip=cookie_context.get_asset(rbx_asset::cookie::GetAssetRequest{
 				asset_id:asset_response.assetId,
 				version:None,
 			}).await.map_err(DownloadDecalError::Get)?;
-			let dom=load_dom(std::io::Cursor::new(file)).map_err(DownloadDecalError::LoadDom)?;
+			let dom=maybe_gzip.read_with(load_dom,load_dom).map_err(DownloadDecalError::LoadDom)?;
 			let instance=dom.get_by_ref(
 				*dom.root().children().first().ok_or(DownloadDecalError::NoFirstInstance)?
 			).ok_or(DownloadDecalError::NoFirstInstance)?;
@@ -993,8 +993,8 @@ async fn asset_details(cookie:Cookie,asset_id:AssetID)->AResult<()>{
 
 async fn download_version(cookie:Cookie,asset_id:AssetID,version:Option<u64>,dest:PathBuf)->AResult<()>{
 	let context=CookieContext::new(cookie);
-	let data=context.get_asset(rbx_asset::cookie::GetAssetRequest{asset_id,version}).await?;
-	tokio::fs::write(dest,data).await?;
+	let maybe_gzip=context.get_asset(rbx_asset::cookie::GetAssetRequest{asset_id,version}).await?;
+	tokio::fs::write(dest,maybe_gzip.to_vec()?).await?;
 	Ok(())
 }
 
@@ -1006,9 +1006,9 @@ async fn download_version_v2(cookie:Cookie,asset_id:AssetID,version:Option<u64>,
 	println!("version:{}",info.version);
 
 	let location=info.info.locations.first().ok_or(anyhow::Error::msg("No locations"))?;
-	let data=context.get_asset_v2_download(location).await?;
+	let maybe_gzip=context.get_asset_v2_download(location).await?;
 
-	tokio::fs::write(dest,data).await?;
+	tokio::fs::write(dest,maybe_gzip.to_vec()?).await?;
 	Ok(())
 }
 
@@ -1024,7 +1024,7 @@ async fn download_list(cookie:Cookie,asset_id_file_map:AssetIDFileMap)->AResult<
 	.buffer_unordered(CONCURRENT_REQUESTS)
 	.for_each(|b:AResult<_>|async{
 			match b{
-				Ok((dest,data))=>if let Err(e)=tokio::fs::write(dest,data).await{
+				Ok((dest,maybe_gzip))=>if let Err(e)=(async||{tokio::fs::write(dest,maybe_gzip.to_vec()?).await})().await{
 					eprintln!("fs error: {}",e);
 				},
 				Err(e)=>eprintln!("dl error: {}",e),
@@ -1228,9 +1228,9 @@ async fn download_history(mut config:DownloadHistoryConfig)->AResult<()>{
 			let mut path=output_folder.clone();
 			path.push(format!("{}_v{}.rbxl",config.asset_id,version_number));
 			join_set.spawn(async move{
-				let file=context.get_asset(rbx_asset::cookie::GetAssetRequest{asset_id:config.asset_id,version:Some(version_number)}).await?;
+				let maybe_gzip=context.get_asset(rbx_asset::cookie::GetAssetRequest{asset_id:config.asset_id,version:Some(version_number)}).await?;
 
-				tokio::fs::write(path,file).await?;
+				tokio::fs::write(path,maybe_gzip.to_vec()?).await?;
 
 				Ok::<_,anyhow::Error>(())
 			});
@@ -1350,9 +1350,9 @@ struct DownloadDecompileConfig{
 
 async fn download_decompile(config:DownloadDecompileConfig)->AResult<()>{
 	let context=CookieContext::new(config.cookie);
-	let file=context.get_asset(rbx_asset::cookie::GetAssetRequest{asset_id:config.asset_id,version:None}).await?;
+	let maybe_gzip=context.get_asset(rbx_asset::cookie::GetAssetRequest{asset_id:config.asset_id,version:None}).await?;
 
-	let dom=load_dom(std::io::Cursor::new(file))?;
+	let dom=maybe_gzip.read_with(load_dom,load_dom)?;
 	let context=rox_compiler::DecompiledContext::from_dom(dom);
 
 	context.write_files(rox_compiler::WriteConfig{
@@ -1532,8 +1532,8 @@ async fn download_and_decompile_history_into_git(config:DownloadAndDecompileHist
 	.map(|asset_version|{
 		let context=context.clone();
 		tokio::task::spawn(async move{
-			let file=context.get_asset(rbx_asset::cookie::GetAssetRequest{asset_id,version:Some(asset_version.assetVersionNumber)}).await?;
-			let dom=load_dom(std::io::Cursor::new(file))?;
+			let maybe_gzip=context.get_asset(rbx_asset::cookie::GetAssetRequest{asset_id,version:Some(asset_version.assetVersionNumber)}).await?;
+			let dom=maybe_gzip.read_with(load_dom,load_dom)?;
 			Ok::<_,anyhow::Error>((asset_version,rox_compiler::DecompiledContext::from_dom(dom)))
 		})
 	}))

From 091a2a92f177d16dc21975416f17de736194c4f2 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 10 Apr 2025 16:48:39 -0700
Subject: [PATCH 7/8] rbx_asset: v0.4.4 parse string ints + save intermediate
 allocation

---
 Cargo.lock           | 2 +-
 rbx_asset/Cargo.toml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index c020c03..3648a8f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1293,7 +1293,7 @@ dependencies = [
 
 [[package]]
 name = "rbx_asset"
-version = "0.4.3"
+version = "0.4.4"
 dependencies = [
  "bytes",
  "chrono",
diff --git a/rbx_asset/Cargo.toml b/rbx_asset/Cargo.toml
index 0120817..d41d068 100644
--- a/rbx_asset/Cargo.toml
+++ b/rbx_asset/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "rbx_asset"
-version = "0.4.3"
+version = "0.4.4"
 edition = "2021"
 publish = ["strafesnet"]
 repository = "https://git.itzana.me/StrafesNET/asset-tool"

From 450b6a0829afbf89b05960c90c2d75673c1ba365 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 10 Apr 2025 17:26:47 -0700
Subject: [PATCH 8/8] update deps

---
 Cargo.lock | 44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 3648a8f..43c352e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -212,9 +212,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
 
 [[package]]
 name = "cc"
-version = "1.2.17"
+version = "1.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
+checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
 dependencies = [
  "jobserver",
  "libc",
@@ -378,9 +378,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "errno"
-version = "0.3.10"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
+checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
 dependencies = [
  "libc",
  "windows-sys 0.59.0",
@@ -874,9 +874,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.8.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
+checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -997,9 +997,9 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.9.3"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
 
 [[package]]
 name = "litemap"
@@ -1056,9 +1056,9 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.6"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29c72f6929239626840b28f919ce8981a317fc5dc63ce25c30d2ab372f94886f"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
 dependencies = [
  "adler2",
 ]
@@ -1117,9 +1117,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
 name = "openssl"
-version = "0.10.71"
+version = "0.10.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd"
+checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
 dependencies = [
  "bitflags 2.9.0",
  "cfg-if",
@@ -1149,9 +1149,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.106"
+version = "0.9.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
+checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
 dependencies = [
  "cc",
  "libc",
@@ -1524,9 +1524,9 @@ dependencies = [
 
 [[package]]
 name = "rustls"
-version = "0.23.25"
+version = "0.23.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c"
+checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0"
 dependencies = [
  "once_cell",
  "rustls-pki-types",
@@ -1666,9 +1666,9 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.14.0"
+version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
+checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
 
 [[package]]
 name = "socket2"
@@ -1795,9 +1795,9 @@ dependencies = [
 
 [[package]]
 name = "tokio"
-version = "1.44.1"
+version = "1.44.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
+checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
 dependencies = [
  "backtrace",
  "bytes",
@@ -2311,9 +2311,9 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
 
 [[package]]
 name = "xml-rs"
-version = "0.8.25"
+version = "0.8.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4"
+checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda"
 
 [[package]]
 name = "yoke"