186 lines
5.2 KiB
TypeScript
186 lines
5.2 KiB
TypeScript
/**
|
|
* Bridge helpers for the drop classification Tauri commands.
|
|
*
|
|
* These wrap the Tauri `invoke()` calls so the frontend can classify
|
|
* dropped files, scan launcher instances, and detect file locks.
|
|
*/
|
|
import type { ClassificationResult } from '@modrinth/ui'
|
|
import { invoke } from '@tauri-apps/api/core'
|
|
|
|
/**
|
|
* Information about a process that has a file handle open.
|
|
*/
|
|
export interface LockingProcess {
|
|
pid: number
|
|
name: string
|
|
path: string
|
|
start_time: string | null
|
|
}
|
|
|
|
/**
|
|
* Classify a dropped file or folder by its path on disk.
|
|
*
|
|
* @param path Absolute filesystem path to the dropped item
|
|
* @returns Classification result indicating what kind of content it is
|
|
*/
|
|
export function classifyDroppedItem(
|
|
path: string,
|
|
allowNestedExtraction = false,
|
|
): Promise<ClassificationResult> {
|
|
return invoke('plugin:drop|drop_classify', { path, allowNestedExtraction })
|
|
}
|
|
|
|
/**
|
|
* Classify a dropped ZIP file by extracting it to a temporary directory first.
|
|
*
|
|
* This is a potentially **long-running** operation — the UI MUST prompt the
|
|
* user before calling this, since extraction can take significant time for
|
|
* large archives.
|
|
*
|
|
* Only call this when [`classifyDroppedItem`] returned `Unknown` with a reason
|
|
* containing "extraction".
|
|
*
|
|
* @param path Absolute filesystem path to the ZIP file
|
|
* @returns Classification result after extraction and analysis
|
|
*/
|
|
export function classifyDroppedItemWithExtraction(path: string): Promise<ClassificationResult> {
|
|
return invoke('plugin:drop|drop_classify_extract', { path })
|
|
}
|
|
|
|
/**
|
|
* Extract a ZIP archive into a fresh temporary directory and return its path.
|
|
*
|
|
* Used for compressed launcher folders (e.g. a zipped `.minecraft`): the
|
|
* instance scan and import then operate on the extraction, so the archive is
|
|
* unpacked exactly once. Call [`removeTempDir`] when the flow finishes.
|
|
*
|
|
* @param zipPath Absolute path to the ZIP archive
|
|
* @returns Absolute path of the extraction directory
|
|
*/
|
|
export function extractZipToTemp(zipPath: string): Promise<string> {
|
|
return invoke('plugin:drop|drop_extract_zip_to_temp', { zipPath })
|
|
}
|
|
|
|
/**
|
|
* Remove a temporary directory created by [`extractZipToTemp`].
|
|
*
|
|
* @param path Absolute path of the extraction directory
|
|
*/
|
|
export function removeTempDir(path: string): Promise<void> {
|
|
return invoke('plugin:drop|drop_remove_temp_dir', { path })
|
|
}
|
|
|
|
/**
|
|
* Metadata about a single importable instance within a launcher.
|
|
*/
|
|
export interface ScanInstance {
|
|
name: string
|
|
/** Resolved filesystem path (informational — the backend resolves it) */
|
|
path: string
|
|
/** Minecraft version, if known (empty string otherwise) */
|
|
version: string
|
|
/** Mod loader, if known (e.g. "fabric", "forge"; empty string otherwise) */
|
|
loader: string
|
|
/** Whether this instance qualifies for compatible mode import */
|
|
compatibleMode?: boolean
|
|
/** For compatible mode: path to the version subfolder containing the JSON */
|
|
versionPath?: string
|
|
}
|
|
|
|
/**
|
|
* Result of scanning a single launcher type for importable instances.
|
|
*/
|
|
export interface ScanResult {
|
|
launcherName: string
|
|
launcherType: string
|
|
instances: ScanInstance[]
|
|
}
|
|
|
|
/**
|
|
* Scan a launcher's data directory for importable Minecraft instances.
|
|
*
|
|
* @param launcherType Launcher type name (e.g. "MultiMC", "PrismLauncher", "HMCL")
|
|
* @param basePath Root directory of the launcher's data
|
|
* @returns List of scan results (one entry per launcher type)
|
|
*/
|
|
export async function scanLauncherInstances(
|
|
launcherType: string,
|
|
basePath: string,
|
|
): Promise<ScanResult[]> {
|
|
const instances: {
|
|
name: string
|
|
path: string
|
|
compatibleMode?: boolean
|
|
versionPath?: string
|
|
}[] = await invoke('plugin:drop|drop_scan_launcher_instances', {
|
|
launcherType,
|
|
basePath,
|
|
})
|
|
|
|
return [
|
|
{
|
|
launcherName: launcherType,
|
|
launcherType,
|
|
instances: instances.map((inst) => ({
|
|
name: inst.name,
|
|
path: inst.path,
|
|
version: '',
|
|
loader: '',
|
|
compatibleMode: inst.compatibleMode,
|
|
versionPath: inst.versionPath,
|
|
})),
|
|
},
|
|
]
|
|
}
|
|
|
|
/**
|
|
* Detect processes holding a file lock on the given path.
|
|
*
|
|
* @param path Absolute path to the file to check
|
|
* @returns List of locking processes (empty if unavailable or none found)
|
|
*/
|
|
export function detectFileLock(path: string): Promise<LockingProcess[]> {
|
|
return invoke('plugin:drop|drop_detect_file_lock', { path })
|
|
}
|
|
|
|
/**
|
|
* Extract mod metadata from a JAR file without installing it.
|
|
*
|
|
* @param path Absolute path to the JAR file
|
|
* @returns JSON string of LocalModMetadata, or null if no metadata found
|
|
*/
|
|
export function extractModMetadata(path: string): Promise<string | null> {
|
|
return invoke('plugin:drop|drop_extract_mod_metadata', { path })
|
|
}
|
|
|
|
/**
|
|
* Metadata extracted from a mod JAR file.
|
|
*/
|
|
export interface LocalModMetadata {
|
|
mod_id: string
|
|
name?: string
|
|
version?: string
|
|
authors?: string[]
|
|
description?: string
|
|
url?: string
|
|
icon_path?: string
|
|
minecraft_version?: string
|
|
loader_version?: string
|
|
loader?: string
|
|
}
|
|
|
|
export interface ModrinthLookupResult {
|
|
hash: string
|
|
project_id: string
|
|
version_id: string
|
|
project_name?: string
|
|
project_slug?: string
|
|
version_number?: string
|
|
game_versions: string[]
|
|
loaders: string[]
|
|
}
|
|
|
|
export async function lookupModHash(path: string): Promise<ModrinthLookupResult | null> {
|
|
return invoke('plugin:drop|drop_lookup_mod_hash', { path })
|
|
}
|