Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"format": "prettier --write .",
"format:check": "prettier --check .",
"check": "npm run typecheck && npm run lint && npm run format:check",
"prepare": "husky"
"prepare": "husky",
"generate:types": "cd src-tauri && cargo test export_bindings --no-fail-fast"
},
"lint-staged": {
"*.{ts,tsx}": [
Expand Down
2 changes: 2 additions & 0 deletions src-tauri/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[env]
TS_RS_EXPORT_DIR = { value = "../src/lib/bindings/", relative = true }
2 changes: 2 additions & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ libloading = "0.9.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1"

ts-rs = { version = "12", features = ["chrono-impl", "serde-json-impl"] }

thiserror = "2"
anyhow = "1"

Expand Down
4 changes: 3 additions & 1 deletion src-tauri/src/commands/app.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::error::IpcResult;
use serde::Serialize;
use ts_rs::TS;

#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct AppInfo {
pub name: String,
Expand Down
10 changes: 8 additions & 2 deletions src-tauri/src/commands/patcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,29 @@ use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::thread;
use tauri::{AppHandle, Emitter, Manager, State};
use ts_rs::TS;

/// Configuration for starting the patcher.
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct PatcherConfig {
/// Optional log file path.
#[ts(optional)]
pub log_file: Option<String>,
/// Timeout in milliseconds for hook initialization. Defaults to 5 minutes.
#[ts(optional)]
pub timeout_ms: Option<u32>,
/// Optional legacy patcher flags (matches `cslol_set_flags`).
///
/// If not provided, defaults to 0 (equivalent to `--opts:none` in cslol-tools).
#[ts(optional, type = "number")]
pub flags: Option<u64>,
}

/// Current status of the patcher.
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct PatcherStatus {
/// Whether the patcher is currently running.
Expand Down
8 changes: 6 additions & 2 deletions src-tauri/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use serde::{Deserialize, Serialize};
use thiserror::Error;
use ts_rs::TS;

/// Error codes that can be communicated across the IPC boundary.
/// These are serialized as SCREAMING_SNAKE_CASE for TypeScript consumption.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)]
#[ts(export)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ErrorCode {
/// File system I/O error
Expand Down Expand Up @@ -46,7 +48,8 @@ pub enum ErrorCode {

/// Structured error response sent over IPC.
/// This provides rich error information to the frontend.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export, rename = "AppError")]
#[serde(rename_all = "camelCase")]
pub struct AppErrorResponse {
/// Machine-readable error code for pattern matching
Expand All @@ -55,6 +58,7 @@ pub struct AppErrorResponse {
pub message: String,
/// Optional contextual data (e.g., the invalid path, missing mod ID)
#[serde(skip_serializing_if = "Option::is_none")]
#[ts(optional, type = "unknown")]
pub context: Option<serde_json::Value>,
}

Expand Down
7 changes: 5 additions & 2 deletions src-tauri/src/mods/inspect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ use ltk_modpkg::Modpkg;
use serde::Serialize;
use std::collections::BTreeMap;
use std::path::Path;
use ts_rs::TS;

/// Information returned by `inspect_modpkg`.
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct ModpkgInfo {
pub name: String,
Expand All @@ -18,7 +20,8 @@ pub struct ModpkgInfo {
pub total_size: u64,
}

#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct LayerInfo {
pub name: String,
Expand Down
4 changes: 3 additions & 1 deletion src-tauri/src/mods/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ use std::fs;
use std::io::{Read, Write};
use std::path::Path;
use tauri::{AppHandle, Emitter};
use ts_rs::TS;

use super::{BulkInstallResult, MigrationPhase, MigrationProgress, ModLibrary};

/// Metadata for a discovered cslol-manager mod, shown in the UI selection step.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct CslolModInfo {
pub folder_name: String,
Expand Down
28 changes: 19 additions & 9 deletions src-tauri/src/mods/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use serde::{Deserialize, Serialize};
use std::fs;
use std::path::{Path, PathBuf};
use tauri::AppHandle;
use ts_rs::TS;
use uuid::Uuid;

/// Managed struct that encapsulates mod library operations.
Expand Down Expand Up @@ -94,7 +95,8 @@ impl ModLibrary {
}

/// Slugified profile name used as the filesystem directory name.
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, TS)]
#[ts(export)]
#[serde(transparent)]
pub struct ProfileSlug(pub String);

Expand Down Expand Up @@ -135,7 +137,8 @@ impl From<String> for ProfileSlug {
}

/// A mod profile for organizing different mod configurations.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct Profile {
/// Unique identifier (UUID)
Expand All @@ -156,7 +159,8 @@ pub struct Profile {
}

/// A mod layer shown in the UI.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct ModLayer {
pub name: String,
Expand All @@ -165,7 +169,8 @@ pub struct ModLayer {
}

/// A mod entry shown in the UI Library.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct InstalledMod {
pub id: String,
Expand All @@ -185,15 +190,17 @@ pub struct InstalledMod {
}

/// Result of a bulk mod install operation.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct BulkInstallResult {
pub installed: Vec<InstalledMod>,
pub failed: Vec<BulkInstallError>,
}

/// Error info for a single file that failed during bulk install.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct BulkInstallError {
pub file_path: String,
Expand All @@ -202,7 +209,8 @@ pub struct BulkInstallError {
}

/// Progress event emitted per-file during bulk mod install.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct InstallProgress {
pub current: usize,
Expand All @@ -211,7 +219,8 @@ pub struct InstallProgress {
}

/// Progress event emitted during cslol migration (both packaging and installing phases).
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct MigrationProgress {
pub phase: MigrationPhase,
Expand All @@ -220,7 +229,8 @@ pub struct MigrationProgress {
pub current_file: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub enum MigrationPhase {
Packaging,
Expand Down
28 changes: 20 additions & 8 deletions src-tauri/src/overlay/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,23 @@ use camino::Utf8PathBuf;
use std::path::PathBuf;
use tauri::Emitter;

#[derive(Clone, serde::Serialize, ts_rs::TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub enum OverlayStage {
Indexing,
Collecting,
Patching,
Strings,
Complete,
}

/// Progress event emitted during overlay building.
#[derive(Clone, serde::Serialize)]
#[derive(Clone, serde::Serialize, ts_rs::TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct OverlayProgress {
pub stage: String,
pub stage: OverlayStage,
pub current_file: Option<String>,
pub current: u32,
pub total: u32,
Expand Down Expand Up @@ -71,17 +83,17 @@ pub fn ensure_overlay(library: &ModLibrary, settings: &Settings) -> AppResult<Pa
.with_progress(move |progress| {
// Convert ltk_overlay progress to our format
let stage = match progress.stage {
ltk_overlay::OverlayStage::Indexing => "indexing",
ltk_overlay::OverlayStage::CollectingOverrides => "collecting",
ltk_overlay::OverlayStage::PatchingWad => "patching",
ltk_overlay::OverlayStage::ApplyingStringOverrides => "strings",
ltk_overlay::OverlayStage::Complete => "complete",
ltk_overlay::OverlayStage::Indexing => OverlayStage::Indexing,
ltk_overlay::OverlayStage::CollectingOverrides => OverlayStage::Collecting,
ltk_overlay::OverlayStage::PatchingWad => OverlayStage::Patching,
ltk_overlay::OverlayStage::ApplyingStringOverrides => OverlayStage::Strings,
ltk_overlay::OverlayStage::Complete => OverlayStage::Complete,
};

let _ = app_handle_clone.emit(
"overlay-progress",
OverlayProgress {
stage: stage.to_string(),
stage,
current_file: progress.current_file,
current: progress.current,
total: progress.total,
Expand Down
4 changes: 3 additions & 1 deletion src-tauri/src/patcher/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ use std::sync::{Arc, Mutex};
use std::thread::JoinHandle;

use serde::Serialize;
use ts_rs::TS;

/// Current phase of the patcher lifecycle.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub enum PatcherPhase {
Idle,
Expand Down
Loading