Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
5c8682d199 | |||
5b8effd7c4 | |||
2c84ebb87e | |||
532257ffb0 | |||
affa6d8535 | |||
6ec89497cb | |||
3122d324bf | |||
7fa38cf8b6 | |||
201bad4074 | |||
cdbf1bdcef | |||
7a4eb4694b | |||
be2c15be39 | |||
6697c38af0 | |||
dce77e1e3d | |||
4d1656f618 | |||
c0a340225d | |||
c0990b3fe8 | |||
6869f97eea | |||
a2ca88b9cd | |||
463e66bd97 | |||
e8c92cf7f0 | |||
6cdf71b5b6 | |||
4d2ed01cc0 | |||
5ecbf08c0a |
14
index.html
Normal file
14
index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Tauri + React + TS</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
27
package.json
Normal file
27
package.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "Launcher-tauri",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.4.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.4.0",
|
||||
"@types/node": "^18.7.10",
|
||||
"@types/react": "^18.0.15",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@vitejs/plugin-react": "^3.0.0",
|
||||
"@welldone-software/why-did-you-render": "^7.0.1",
|
||||
"typescript": "^4.9.5",
|
||||
"vite": "^4.2.1"
|
||||
}
|
||||
}
|
2271
src-tauri/Cargo.lock
generated
2271
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,12 @@
|
||||
[package]
|
||||
name = "Launcher-tauri"
|
||||
name = "launcher-tauri"
|
||||
version = "0.0.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
edition = "2021"
|
||||
rust-version = "1.57"
|
||||
rust-version = "1.64"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -16,20 +16,26 @@ tauri-build = {version = "1.2", features = [] }
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = {version = "1.2", features = ["api-all"] }
|
||||
tauri = {version = "1.2", features = [ "shell-open"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
uuid = "1.2.2"
|
||||
log4rs = "1.2.0"
|
||||
reqwest = { version = "0.11.13", default-features = true, features = ["json"] }
|
||||
reqwest = { version = "0.11.13", default-features = true, features = ["json", "blocking"] }
|
||||
urlencoding = "2.1.2"
|
||||
warp = "0.3.3"
|
||||
anyhow = "1.0.66"
|
||||
rand = "0.8.5"
|
||||
directories = "5.0.0"
|
||||
sha256 = "1.4.0"
|
||||
tokio-tar = "0.3.1"
|
||||
async_zip = { version = "0.0.15", features = ["full"] }
|
||||
tokio-stream = "0.1.14"
|
||||
sha1 = "0.10.6"
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
||||
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
||||
default = [ "custom-protocol" ]
|
||||
default = ["custom-protocol"]
|
||||
# this feature is used used for production builds where `devPath` points to the filesystem
|
||||
# DO NOT remove this
|
||||
custom-protocol = [ "tauri/custom-protocol" ]
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
@ -3,6 +3,7 @@ use std::{fmt, net::TcpListener, sync::Arc};
|
||||
use rand::{thread_rng, Rng};
|
||||
use reqwest::{header::{CONTENT_TYPE, CONNECTION, ACCEPT, AUTHORIZATION}, Client};
|
||||
use serde_json::{Value, json};
|
||||
use tauri::{WindowEvent, async_runtime::spawn_blocking};
|
||||
use tokio::{sync::mpsc, join};
|
||||
use urlencoding::encode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -33,6 +34,7 @@ pub struct OauthToken {
|
||||
prompt: Arc<Prompt>
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct AccessRefreshToken {
|
||||
access_token: String,
|
||||
refresh_token: String
|
||||
@ -50,6 +52,14 @@ pub struct ReceivedCode {
|
||||
pub state: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct GameProfile {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub skins: Vec<Value>,
|
||||
pub capes: Vec<Value>,
|
||||
}
|
||||
|
||||
pub struct Authentification;
|
||||
|
||||
impl Authentification {
|
||||
@ -66,6 +76,11 @@ impl Authentification {
|
||||
format!("https://login.live.com/oauth20_authorize.srf?client_id={}&response_type=code&redirect_uri={}&scope=Xboxlive.signin+Xboxlive.offline_access&prompt={}&state={}", token.client_id, encode(token.redirect.as_str()), token.prompt, state)
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
fn send_blocking(sender: tokio::sync::mpsc::Sender<bool>) {
|
||||
sender.blocking_send(true);
|
||||
}
|
||||
|
||||
async fn fetch_oauth2_token(prompt: Prompt, app: tauri::AppHandle) -> Result<(ReceivedCode, OauthToken)> {
|
||||
let state: String = thread_rng()
|
||||
.sample_iter(&rand::distributions::Alphanumeric)
|
||||
@ -93,14 +108,37 @@ impl Authentification {
|
||||
"externam",
|
||||
tauri::WindowUrl::External(link.parse().unwrap())
|
||||
).build().expect("Failed to build window");
|
||||
let received = Self::listen(port_holder.unwrap()).await?;
|
||||
second_window.close()?;
|
||||
|
||||
if received.state != state {
|
||||
bail!("CSRF check fail")
|
||||
let (sender, mut receiver) = mpsc::channel::<bool>(2);
|
||||
second_window.on_window_event(move|e| {
|
||||
match e {
|
||||
WindowEvent::Destroyed => {
|
||||
let sender = sender.clone();
|
||||
spawn_blocking(|| Self::send_blocking(sender));
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
let listener = Self::listen(port_holder.unwrap());
|
||||
tokio::select! {
|
||||
received = listener => {
|
||||
match received {
|
||||
Ok(received) => {
|
||||
second_window.close()?;
|
||||
|
||||
if received.state != state {
|
||||
bail!("CSRF check fail")
|
||||
}
|
||||
Ok((received, token_data))
|
||||
},
|
||||
Err(err) => {
|
||||
bail!(err)
|
||||
}
|
||||
}
|
||||
},
|
||||
_ = receiver.recv() => {
|
||||
bail!("You closed the window before completion")
|
||||
}
|
||||
}
|
||||
|
||||
Ok((received, token_data))
|
||||
}
|
||||
|
||||
// fn create_link_from_prompt(prompt: Prompt) -> String {
|
||||
@ -233,7 +271,7 @@ impl Authentification {
|
||||
}
|
||||
}
|
||||
|
||||
async fn fetch_minecraft_profile(mc_token: &String, reqwest_client: &Client) -> Result<(String, String)> {
|
||||
async fn fetch_minecraft_profile(mc_token: &String, reqwest_client: &Client) -> Result<GameProfile> {
|
||||
let received: Value = reqwest_client
|
||||
.get("https://api.minecraftservices.com/minecraft/profile")
|
||||
.header(AUTHORIZATION, format!("Bearer {}", mc_token))
|
||||
@ -245,11 +283,15 @@ impl Authentification {
|
||||
if let Some(val) = received.get("error") {
|
||||
bail!(String::from(val.as_str().unwrap()))
|
||||
} else {
|
||||
Ok((String::from(received["id"].as_str().unwrap()), String::from(received["name"].as_str().unwrap())))
|
||||
let received: GameProfile = match serde_json::from_value(received) {
|
||||
Ok(gp) => gp,
|
||||
Err(err) => bail!(err),
|
||||
};
|
||||
Ok(received)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn login(prompt: Prompt, app: tauri::AppHandle) -> Result<(String, String)> {
|
||||
pub async fn login(prompt: Prompt, app: tauri::AppHandle) -> Result<GameProfile> {
|
||||
let reqwest_client = Client::new();
|
||||
let oauth_token = Self::fetch_oauth2_token(prompt, app).await?;
|
||||
let access_refresh_token = Self::fetch_token(oauth_token.0, oauth_token.1, &reqwest_client).await?;
|
||||
|
28
src-tauri/src/launcher/altarik/custom_version_manifest.rs
Normal file
28
src-tauri/src/launcher/altarik/custom_version_manifest.rs
Normal file
@ -0,0 +1,28 @@
|
||||
//! module for fabric version detail manifest
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CustomVersionManifest {
|
||||
#[serde(rename(serialize = "inheritsFrom", deserialize = "inheritsFrom"))]
|
||||
pub inherits_from: String,
|
||||
#[serde(rename(serialize = "mainClass", deserialize = "mainClass"))]
|
||||
pub main_class: String,
|
||||
pub libraries: Vec<CustomLibrary>,
|
||||
pub arguments: CustomArguments,
|
||||
pub id: String,
|
||||
#[serde(rename(serialize = "type", deserialize = "type"))]
|
||||
pub t_type: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CustomLibrary {
|
||||
pub name: String,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CustomArguments {
|
||||
jvm: Vec<String>,
|
||||
game: Vec<String>,
|
||||
}
|
277
src-tauri/src/launcher/altarik/mod.rs
Normal file
277
src-tauri/src/launcher/altarik/mod.rs
Normal file
@ -0,0 +1,277 @@
|
||||
pub mod custom_version_manifest;
|
||||
|
||||
use std::path::{PathBuf, Path};
|
||||
|
||||
use anyhow::{Result, bail, anyhow};
|
||||
use reqwest::Client;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use async_zip::base::read::seek::ZipFileReader;
|
||||
use sha1::{Digest, Sha1};
|
||||
use tokio::{fs::{OpenOptions, File, self}, sync::mpsc, io::{AsyncWriteExt, AsyncReadExt}};
|
||||
use tokio_tar::Archive;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use crate::launcher::ProgressMessage;
|
||||
|
||||
use self::custom_version_manifest::CustomVersionManifest;
|
||||
|
||||
use super::{ACTUAL_OS, manifest::{OSName, VersionDetail}};
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct AltarikManifest {
|
||||
pub chapters: Vec<Chapter>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Chapter {
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
#[serde(rename(serialize = "minecraftVersion", deserialize = "minecraftVersion"))]
|
||||
pub minecraft_version: String,
|
||||
#[serde(rename(serialize = "type", deserialize = "type"))]
|
||||
pub mc_type: String,
|
||||
#[serde(rename(serialize = "customVersion", deserialize = "customVersion"))]
|
||||
pub custom_version: String,
|
||||
pub modspack: ModsPack,
|
||||
pub java: Java,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct ModsPack {
|
||||
pub mods: Vec<String>,
|
||||
pub sha1sum: Vec<String>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Java {
|
||||
pub platform: JavaPlatform,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct JavaPlatform {
|
||||
pub win32: Option<JavaPlatformArch>,
|
||||
pub linux: Option<JavaPlatformArch>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct JavaPlatformArch {
|
||||
pub x64: JavaDetails
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct JavaDetails {
|
||||
pub name: String,
|
||||
pub link: String,
|
||||
pub sha256sum: String,
|
||||
}
|
||||
|
||||
impl AltarikManifest {
|
||||
|
||||
pub async fn get_altarik_manifest(reqwest: &Client) -> Result<AltarikManifest> {
|
||||
let received: AltarikManifest = reqwest
|
||||
.get("https://launcher.altarik.fr")
|
||||
.send()
|
||||
.await?
|
||||
.json()
|
||||
.await?;
|
||||
Ok(received)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Chapter {
|
||||
|
||||
pub async fn get_custom_version_detail_manifest(&self, version_dir: &PathBuf) -> Result<CustomVersionManifest> {
|
||||
let filepath = version_dir.join(self.custom_version.to_string()).join(format!("{}.json", self.custom_version.to_string()));
|
||||
let mut file = File::open(filepath).await?;
|
||||
let mut content = String::new();
|
||||
file.read_to_string(&mut content).await?;
|
||||
Ok(serde_json::from_str(&content)?)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl JavaPlatform {
|
||||
|
||||
pub async fn download_java(&self, root_path: &Path, reqwest: &Client, log_channel: mpsc::Sender<ProgressMessage>) -> Result<()> {
|
||||
let download_path = root_path.join("runtime").join("download");
|
||||
let (url, extension) = match ACTUAL_OS {
|
||||
OSName::Linux => (self.linux.clone(), "tar.gz"),
|
||||
OSName::Windows => (self.win32.clone(), "zip"),
|
||||
_ => bail!("Your current is not supported")
|
||||
};
|
||||
let url = match url {
|
||||
Some(url) => url,
|
||||
None => bail!("No available executable available for your platform")
|
||||
};
|
||||
|
||||
let filepath = download_path.join(format!("{}.{}", url.x64.name.clone(), extension));
|
||||
let mut should_download = false;
|
||||
if !filepath.exists() {
|
||||
should_download = true;
|
||||
} else {
|
||||
let hash = sha256::try_digest(filepath.clone());
|
||||
match hash {
|
||||
Ok(hash) => {
|
||||
if hash != url.x64.sha256sum {
|
||||
println!("Hash of java archive is not correct, redownloading");
|
||||
should_download = true;
|
||||
}
|
||||
},
|
||||
Err(_) => should_download = true
|
||||
}
|
||||
}
|
||||
if should_download {
|
||||
println!("Downloading java");
|
||||
if filepath.exists() {
|
||||
fs::remove_file(filepath.clone()).await?; // remove content before writing and appending to it
|
||||
}
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.append(true)
|
||||
.create(true)
|
||||
.open(filepath)
|
||||
.await?;
|
||||
let mut res = reqwest.get(url.x64.link.clone()).send().await?;
|
||||
log_channel.send(ProgressMessage { p_type: String::from("java"), current: 0, total: 100 }).await?;
|
||||
let length = if let Some(length) = res.content_length() {
|
||||
length as usize
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let mut downloaded_size = 0;
|
||||
while let Some(chunk) = res.chunk().await? {
|
||||
downloaded_size += chunk.len();
|
||||
file.write_all(&chunk).await?;
|
||||
log_channel.send(ProgressMessage { p_type: String::from("java"), current: if length != 0 { downloaded_size / length } else { 0 }, total: 100 }).await?;
|
||||
}
|
||||
println!("{} downloaded", url.x64.name)
|
||||
} else {
|
||||
println!("{} already downloaded", url.x64.name)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn extract_java(&self, root_path: &Path) -> Result<()> {
|
||||
let (url, extension) = match ACTUAL_OS {
|
||||
OSName::Linux => (self.linux.clone(), "tar.gz"),
|
||||
OSName::Windows => (self.win32.clone(), "zip"),
|
||||
_ => bail!("Your current is not supported")
|
||||
};
|
||||
let url = match url {
|
||||
Some(url) => url,
|
||||
None => bail!("No available executable available for your platform")
|
||||
};
|
||||
let archive_path = root_path.join("runtime").join("download").join(format!("{}.{}", url.x64.name, extension));
|
||||
let extract_path = root_path.join("runtime");
|
||||
extract_zip(&archive_path, &extract_path).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl ModsPack {
|
||||
|
||||
|
||||
pub async fn download_mods(&self, reqwest: &Client, modpack_dir: &PathBuf, root_dir: &PathBuf, log_channel: mpsc::Sender<ProgressMessage>) -> Result<()> {
|
||||
for index in 0..self.mods.len() {
|
||||
log_channel.send(ProgressMessage { p_type: "mods".to_string(), current: index, total: self.mods.len() }).await?;
|
||||
let mod_url = self.mods.get(index).ok_or(anyhow!("Cannot get mod download link"))?;
|
||||
let sha1 = self.sha1sum.get(index).ok_or(anyhow!("Cannot verify mod integrity"))?;
|
||||
let filepath = modpack_dir.join(format!("modpack{}.zip", index));
|
||||
let should_download = self.should_download_mod(&sha1, &filepath).await?;
|
||||
if should_download {
|
||||
println!("Need to download mod {}", mod_url);
|
||||
let mut res = reqwest.get(mod_url)
|
||||
.send()
|
||||
.await?;
|
||||
let mut file = fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.append(true)
|
||||
.open(filepath.clone())
|
||||
.await?;
|
||||
while let Some(chunk) = res.chunk().await? {
|
||||
file.write_all(&chunk).await?;
|
||||
}
|
||||
} else {
|
||||
println!("Mod {} already downloaded", sha1);
|
||||
}
|
||||
extract_zip(&filepath, &root_dir).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn should_download_mod(&self, mod_sha1: &&String, filepath: &PathBuf) -> Result<bool> {
|
||||
if filepath.exists() {
|
||||
let mut hasher = Sha1::new();
|
||||
let mut file = File::open(filepath).await?;
|
||||
let mut content = Vec::new();
|
||||
file.read_to_end(&mut content).await?;
|
||||
hasher.update(content);
|
||||
let hash = hasher.finalize();
|
||||
// let b16 = base16ct::upper::encode_string(hash);
|
||||
if format!("{:x}", hash.clone()) != mod_sha1.to_lowercase() {
|
||||
println!("Correct: {:?}, current: {:X}", mod_sha1, hash);
|
||||
fs::remove_file(filepath).await?;
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
} else {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
async fn extract_targz(archive_path: PathBuf, extract_path: PathBuf) -> Result<()> {
|
||||
let file = File::open(archive_path.clone()).await?;
|
||||
let mut archive = Archive::new(file);
|
||||
let mut entries = archive.entries()?;
|
||||
while let Some(entry) = entries.next().await {
|
||||
let file = entry?;
|
||||
println!("{:?}", archive_path);
|
||||
println!("{}", file.path()?.to_string_lossy().to_string());
|
||||
// TODO when I'll be on a linux
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn extract_zip(archive_path: &PathBuf, extract_path: &PathBuf) -> Result<()> {
|
||||
// TODO add log_channel to send progression to user
|
||||
let file = File::open(archive_path.clone()).await?;
|
||||
let mut reader = ZipFileReader::with_tokio(file).await?;
|
||||
for index in 0..reader.file().entries().len() {
|
||||
if let Some(entry) = reader.file().entries().get(index) {
|
||||
let entry = entry.entry();
|
||||
let filename = entry.filename().as_str()?;
|
||||
let path = extract_path.join(filename);
|
||||
if entry.dir()? {
|
||||
if path.exists() {
|
||||
fs::remove_dir_all(path.clone()).await?; // clear folder before continue, avoid injection
|
||||
}
|
||||
fs::create_dir_all(path).await?; // recreating the folder then
|
||||
} else {
|
||||
let mut entry_reader = reader.reader_with_entry(index).await?;
|
||||
if path.exists() {
|
||||
fs::remove_file(&path).await?;
|
||||
}
|
||||
let mut writer = OpenOptions::new()
|
||||
.write(true)
|
||||
.append(true)
|
||||
.create_new(true)
|
||||
.open(&path)
|
||||
.await?;
|
||||
let mut buf = Vec::with_capacity(1024 * 128);
|
||||
entry_reader.read_to_end_checked(&mut buf).await?;
|
||||
writer.write_all(&buf).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
147
src-tauri/src/launcher/manifest.rs
Normal file
147
src-tauri/src/launcher/manifest.rs
Normal file
@ -0,0 +1,147 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use reqwest::Client;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::{Value, Map};
|
||||
|
||||
use super::VersionType;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct VersionManifestV2 {
|
||||
latest: Value,
|
||||
versions: Vec<Version>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Version {
|
||||
id: String,
|
||||
#[serde(rename(serialize = "type", deserialize = "type"))]
|
||||
v_type: VersionType,
|
||||
url: String,
|
||||
sha1: String
|
||||
}
|
||||
|
||||
|
||||
pub async fn get_version_manifest(reqwest: &Client) -> Result<VersionManifestV2> {
|
||||
let received: VersionManifestV2 = reqwest
|
||||
.get("https://piston-meta.mojang.com/mc/game/version_manifest_v2.json")
|
||||
.send()
|
||||
.await?
|
||||
.json()
|
||||
.await?;
|
||||
Ok(received)
|
||||
}
|
||||
|
||||
pub async fn get_version_from_manifest<'a>(manifest: &'a VersionManifestV2, game_version: String, version_type: &VersionType) -> Result<&'a Version> {
|
||||
for i in manifest.versions.iter().enumerate() {
|
||||
let id = i.1.id.clone();
|
||||
let v_type = i.1.v_type;
|
||||
if id == game_version && &v_type == version_type {
|
||||
return Ok(i.1);
|
||||
}
|
||||
}
|
||||
bail!("Version not Found")
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct VersionDetail {
|
||||
arguments: Map<String, Value>,
|
||||
#[serde(rename(serialize = "assetIndex", deserialize = "assetIndex"))]
|
||||
pub asset_index: AssetIndex,
|
||||
pub assets: String,
|
||||
#[serde(rename(serialize = "complianceLevel", deserialize = "complianceLevel"))]
|
||||
compliance_level: i32,
|
||||
downloads: Map<String, Value>,
|
||||
id: String,
|
||||
#[serde(rename(serialize = "javaVersion", deserialize = "javaVersion"))]
|
||||
java_version: Map<String, Value>,
|
||||
pub libraries: Vec<Library>,
|
||||
logging: Map<String, Value>,
|
||||
#[serde(rename(serialize = "mainClass", deserialize = "mainClass"))]
|
||||
main_class: String,
|
||||
#[serde(rename(serialize = "type", deserialize = "type"))]
|
||||
v_type: VersionType
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AssetIndex {
|
||||
pub id: String,
|
||||
pub sha1: String,
|
||||
pub size: usize,
|
||||
#[serde(rename(serialize = "totalSize", deserialize = "totalSize"))]
|
||||
pub total_size: usize,
|
||||
pub url: String
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Library {
|
||||
pub downloads: LibraryDownload,
|
||||
pub name: String,
|
||||
pub rules: Option<Vec<LibraryRule>>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LibraryDownload {
|
||||
pub artifact: LibraryArtifact
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LibraryRule {
|
||||
pub action: String,
|
||||
pub os: LibraryOSRule
|
||||
}
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LibraryOSRule {
|
||||
pub name: OSName,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq)]
|
||||
pub enum OSName {
|
||||
#[serde(rename(serialize = "osx", deserialize = "osx"))]
|
||||
MacOsX,
|
||||
#[serde(rename(serialize = "linux", deserialize = "linux"))]
|
||||
Linux,
|
||||
#[serde(rename(serialize = "windows", deserialize = "windows"))]
|
||||
Windows
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LibraryArtifact {
|
||||
pub path: String,
|
||||
pub sha1: String,
|
||||
pub size: u64,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
pub async fn get_version_detail(reqwest: &Client, version : &Version) -> Result<VersionDetail> {
|
||||
let received: VersionDetail = reqwest
|
||||
.get(version.url.clone())
|
||||
.send()
|
||||
.await?
|
||||
.json()
|
||||
.await?;
|
||||
Ok(received)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AssetsManifest {
|
||||
pub objects: HashMap<String, AssetObject>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AssetObject {
|
||||
pub hash: String,
|
||||
pub size: u64,
|
||||
}
|
||||
|
||||
pub async fn get_version_assets(reqwest: &Client , assets_index: &AssetIndex) -> Result<AssetsManifest> {
|
||||
let received: AssetsManifest = reqwest
|
||||
.get(assets_index.url.clone())
|
||||
.send()
|
||||
.await?
|
||||
.json()
|
||||
.await?;
|
||||
Ok(received)
|
||||
}
|
@ -0,0 +1,334 @@
|
||||
mod manifest;
|
||||
pub mod altarik;
|
||||
|
||||
use std::path::{Path, self, PathBuf};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use reqwest::{Client, StatusCode};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use sha1::{Digest, Sha1};
|
||||
use tokio::{fs::{self, File}, io::{AsyncWriteExt, AsyncSeekExt, AsyncReadExt}, sync::mpsc};
|
||||
|
||||
use crate::authentification::GameProfile;
|
||||
|
||||
use self::{manifest::{VersionDetail, get_version_manifest, get_version_from_manifest, get_version_detail, Library, OSName, get_version_assets, AssetsManifest}, altarik::{Chapter, custom_version_manifest::CustomVersionManifest}};
|
||||
|
||||
|
||||
#[cfg(target_os="windows")]
|
||||
const ACTUAL_OS: OSName = OSName::Windows;
|
||||
#[cfg(target_os="linux")]
|
||||
const ACTUAL_OS: OSName = OSName::Linux;
|
||||
#[cfg(target_os="macos")]
|
||||
const ACTUAL_OS: OSName = OSName::MacOsX;
|
||||
|
||||
#[cfg(not(any(target_arch="x86_64", target_arch="x86")))]
|
||||
compile_error!("Your architecture is not supported");
|
||||
|
||||
#[derive(Clone, serde::Serialize, Debug)]
|
||||
pub struct ProgressMessage {
|
||||
p_type: String,
|
||||
current: usize,
|
||||
total: usize,
|
||||
}
|
||||
|
||||
pub struct ClientOptions<'a> {
|
||||
pub authorization: GameProfile,
|
||||
pub log_channel: mpsc::Sender<ProgressMessage>,
|
||||
pub root_path: &'a Path,
|
||||
pub java_path: &'a Path,
|
||||
/// deprecated, will be remove
|
||||
pub version_number: String,
|
||||
pub version_type: VersionType,
|
||||
// version_custom: String, // for a next update
|
||||
pub memory_min: String,
|
||||
pub memory_max: String,
|
||||
}
|
||||
|
||||
pub struct MinecraftClient<'a> {
|
||||
opts: &'a ClientOptions<'a>,
|
||||
details: VersionDetail,
|
||||
custom_details: Option<CustomVersionManifest>,
|
||||
assets: AssetsManifest,
|
||||
reqwest_client: Client,
|
||||
chapter: Chapter,
|
||||
|
||||
}
|
||||
|
||||
impl<'a> MinecraftClient<'_> {
|
||||
pub async fn new(opts: &'a ClientOptions<'a>, chapter: Chapter) -> Result<MinecraftClient<'a>> {
|
||||
let reqwest_client = Client::new();
|
||||
let manifest = Self::load_manifest(&reqwest_client, &opts).await?;
|
||||
let details = manifest.0;
|
||||
let assets = manifest.1;
|
||||
Ok(MinecraftClient {
|
||||
opts,
|
||||
reqwest_client,
|
||||
details,
|
||||
custom_details: None,
|
||||
assets,
|
||||
chapter
|
||||
})
|
||||
}
|
||||
|
||||
async fn load_manifest(reqwest_client: &Client, opts: &ClientOptions<'a>) -> Result<(VersionDetail, AssetsManifest)> {
|
||||
let manifest = get_version_manifest(&reqwest_client).await?;
|
||||
let version = get_version_from_manifest(&manifest, opts.version_number.clone(), &opts.version_type).await?;
|
||||
let details = get_version_detail(&reqwest_client, version).await?;
|
||||
let version_assets = get_version_assets(reqwest_client, &details.asset_index).await?;
|
||||
Ok((details, version_assets))
|
||||
}
|
||||
|
||||
async fn create_dirs(&self) -> Result<()> {
|
||||
let folders = vec![
|
||||
self.opts.root_path.join("libraries"),
|
||||
self.opts.root_path.join("assets").join("objects"),
|
||||
self.opts.root_path.join("assets").join("indexes"),
|
||||
self.opts.root_path.join("runtime").join("download"),
|
||||
self.opts.root_path.join("mods")
|
||||
];
|
||||
let mut tasks = Vec::with_capacity(folders.len());
|
||||
for folder in folders {
|
||||
if !folder.exists() {
|
||||
tasks.push(tokio::spawn(async { fs::create_dir_all(folder).await }));
|
||||
}
|
||||
}
|
||||
for task in tasks {
|
||||
let _ = task.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn save_version_index(&self) -> Result<()> {
|
||||
let indexes = &self.opts.root_path.join("assets").join("indexes");
|
||||
let mut filename = self.details.assets.clone();
|
||||
filename.push_str(".json");
|
||||
let filepath = indexes.join(filename);
|
||||
let file = File::create(filepath).await;
|
||||
match file {
|
||||
Ok(mut f) => {
|
||||
f.write_all(serde_json::to_string(&self.details)?.as_bytes()).await?;
|
||||
Ok(())
|
||||
},
|
||||
Err(err) => bail!(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn download_requirements(&mut self) -> Result<()> {
|
||||
// create root folder if it doesn't exist
|
||||
self.create_dirs().await?;
|
||||
let lib = &self.opts.root_path.join("libraries");
|
||||
let asset = &self.opts.root_path.join("assets").join("objects");
|
||||
let modpack = &self.opts.root_path.join("modpack").join(self.chapter.title.clone());
|
||||
if !modpack.exists() {
|
||||
fs::create_dir_all(modpack).await?;
|
||||
}
|
||||
self.clear_folder().await?;
|
||||
self.save_version_index().await?;
|
||||
self.chapter.java.platform.download_java(self.opts.root_path, &self.reqwest_client, self.opts.log_channel.clone()).await?;
|
||||
self.chapter.java.platform.extract_java(self.opts.root_path).await?;
|
||||
self.chapter.modspack.download_mods(&self.reqwest_client, modpack, &self.opts.root_path.to_path_buf(), self.opts.log_channel.clone()).await?;
|
||||
self.custom_details = Some(self.chapter.get_custom_version_detail_manifest(&self.opts.root_path.join("versions")).await?);
|
||||
self.download_libraries(lib).await?;
|
||||
self.download_custom_libraries(lib).await?;
|
||||
self.download_assets(asset).await?;
|
||||
self.download_jar().await?;
|
||||
self.opts.log_channel.send(ProgressMessage { p_type: "completed".to_string(), current: 0, total: 0 }).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn download_libraries(&mut self, lib: &PathBuf) -> Result<()> {
|
||||
self.filter_non_necessary_librairies();
|
||||
let total = self.details.libraries.len();
|
||||
for (progress, i) in self.details.libraries.iter().enumerate() {
|
||||
|
||||
let p = i.downloads.artifact.path.clone();
|
||||
let mut splited = p.split("/").collect::<Vec<&str>>();
|
||||
let filename = splited.pop().ok_or(anyhow::anyhow!("Invalid filename"))?; // remove last element
|
||||
let p = splited.join(path::MAIN_SEPARATOR_STR);
|
||||
let p = &lib.join(p);
|
||||
fs::create_dir_all(p).await?;
|
||||
let file_path = p.join(filename);
|
||||
let mut file = Self::select_file_option(&file_path, i.downloads.artifact.size).await?;
|
||||
|
||||
let size = file.seek(std::io::SeekFrom::End(0)).await?;
|
||||
file.seek(std::io::SeekFrom::Start(0)).await?;
|
||||
let mut hasher = Sha1::new();
|
||||
let mut content = Vec::new();
|
||||
file.read_to_end(&mut content).await?;
|
||||
hasher.update(content);
|
||||
let hash = hasher.finalize();
|
||||
if size != i.downloads.artifact.size || format!("{:x}", hash) != i.downloads.artifact.sha1.to_lowercase() {
|
||||
let url = i.downloads.artifact.url.clone();
|
||||
|
||||
let mut sha_url = url.clone();
|
||||
sha_url.push_str(".sha1");
|
||||
let sha1 = self.reqwest_client
|
||||
.get(sha_url)
|
||||
.send()
|
||||
.await?;
|
||||
if sha1.status() == StatusCode::OK {
|
||||
let sha1 = sha1.text().await?;
|
||||
if sha1 != i.downloads.artifact.sha1 {
|
||||
bail!("Sha1 {:?} of {} is invalid, a malicious file might be present on the remote server, should be {}", sha1, i.name, i.downloads.artifact.sha1)
|
||||
}
|
||||
}
|
||||
|
||||
let content = self.reqwest_client
|
||||
.get(url)
|
||||
.send()
|
||||
.await?
|
||||
.bytes()
|
||||
.await?;
|
||||
file.write_all(&content).await?;
|
||||
println!("{} downloaded", i.name);
|
||||
} else {
|
||||
println!("{} already downloaded", i.name);
|
||||
}
|
||||
self.opts.log_channel.send( ProgressMessage { p_type: "libraries".to_string(), current: progress + 1, total }).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn download_custom_libraries(&self, lib_dir: &PathBuf) -> Result<()> {
|
||||
if let Some(custom) = &self.custom_details {
|
||||
for i in &custom.libraries {
|
||||
let splited: Vec<&str> = i.name.split(":").collect();
|
||||
if splited.len() == 3 {
|
||||
let file_name = format!("{}-{}.jar", splited[1], splited[2]);
|
||||
let sha256_url = format!("{}.sha256", file_name);
|
||||
let url = format!("{}/{}/{}/{}/{}", i.url, splited[0].replace(".", "/"), splited[1], splited[2], file_name);
|
||||
|
||||
let sha256 = self.reqwest_client
|
||||
.get(sha256_url)
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
let sep = path::MAIN_SEPARATOR_STR;
|
||||
let p = format!("{}{sep}{}{sep}{}{sep}{}", splited[0].replace(".", sep), splited[1], splited[2], splited[1]);
|
||||
let file_path = lib_dir.join(p);
|
||||
if !file_path.exists() {
|
||||
|
||||
}
|
||||
} else {
|
||||
bail!("Cannot resolve dependency url");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn download_jar(&mut self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// delete and recreate some folder, in particular mods and version folder
|
||||
async fn clear_folder(&self) -> Result<()> {
|
||||
for i in [self.opts.root_path.join("mods"), self.opts.root_path.join("versions")] {
|
||||
fs::remove_dir_all(&i).await?;
|
||||
fs::create_dir_all(&i).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn select_file_option(file_path: &PathBuf, expected_size: u64) -> Result<File> {
|
||||
if (&file_path).exists() {
|
||||
let f = fs::File::open(&file_path).await;
|
||||
match f {
|
||||
Ok(mut f) => { if f.seek(std::io::SeekFrom::End(0)).await? == expected_size { Ok(f) } else { Ok(fs::File::create(file_path).await?) } },
|
||||
Err(err) => bail!(err),
|
||||
}
|
||||
} else {
|
||||
Ok(fs::File::create(file_path).await?)
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter non necessary librairies for the current OS
|
||||
fn filter_non_necessary_librairies(&mut self) {
|
||||
self.details.libraries.retain(|e| { Self::should_use_library(e) });
|
||||
}
|
||||
|
||||
async fn download_assets(&mut self, object_folder: &PathBuf) -> Result<()> {
|
||||
let total: usize = self.assets.objects.len();
|
||||
for (progress, (_, value)) in self.assets.objects.iter().enumerate() {
|
||||
let hash = value.hash.clone();
|
||||
let two_hex = hash.chars().take(2).collect::<String>();
|
||||
let hex_folder = object_folder.join(&two_hex);
|
||||
if !hex_folder.exists() {
|
||||
fs::create_dir(&hex_folder).await?;
|
||||
}
|
||||
|
||||
let file_path = hex_folder.join(&hash);
|
||||
let mut file = Self::select_file_option(&file_path, value.size).await?;
|
||||
let size = file.seek(std::io::SeekFrom::End(0)).await?;
|
||||
file.seek(std::io::SeekFrom::Start(0)).await?;
|
||||
|
||||
let mut hasher = Sha1::new();
|
||||
let mut content = Vec::new();
|
||||
file.read_to_end(&mut content).await?;
|
||||
hasher.update(content);
|
||||
let hash_file = hasher.finalize();
|
||||
|
||||
if size != value.size || format!("{:x}", hash_file) != value.hash {
|
||||
let url = format!("https://resources.download.minecraft.net/{}/{}", two_hex, hash);
|
||||
let received = self.reqwest_client
|
||||
.get(url)
|
||||
.send()
|
||||
.await?
|
||||
.bytes()
|
||||
.await?;
|
||||
file.write_all(&received).await?;
|
||||
println!("{} downloaded", value.hash);
|
||||
} else {
|
||||
println!("{} already downloaded", value.hash);
|
||||
}
|
||||
self.opts.log_channel.send( ProgressMessage { p_type: "assets".to_string(), current: progress + 1, total }).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn launch_minecraft(&mut self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn should_use_library(library: &Library) -> bool {
|
||||
match &library.rules {
|
||||
Some(rules) => {
|
||||
for i in rules.iter().enumerate() {
|
||||
let op = if i.1.action == "allow" {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if i.1.os.name == ACTUAL_OS {
|
||||
return op;
|
||||
}
|
||||
}
|
||||
false
|
||||
},
|
||||
None => {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn launch_game(&self) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(PartialEq, Serialize, Deserialize, Debug, Clone, Copy)]
|
||||
pub enum VersionType {
|
||||
#[serde(alias = "release")]
|
||||
Release,
|
||||
#[serde(alias = "snapshot")]
|
||||
Snapshot,
|
||||
#[serde(alias = "old_alpha")]
|
||||
OldAlpha,
|
||||
#[serde(alias = "old_beta")]
|
||||
OldBeta,
|
||||
}
|
@ -4,29 +4,149 @@
|
||||
)]
|
||||
|
||||
pub mod authentification;
|
||||
pub mod launcher;
|
||||
|
||||
use authentification::{Authentification, Prompt};
|
||||
use std::sync::Mutex;
|
||||
|
||||
use authentification::{Authentification, Prompt, GameProfile};
|
||||
use anyhow::Result;
|
||||
use directories::BaseDirs;
|
||||
use launcher::{MinecraftClient, ClientOptions, ProgressMessage, altarik::{AltarikManifest, Chapter}};
|
||||
use reqwest::Client;
|
||||
use tauri::Manager;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
struct CustomState (Option<GameProfile>, Option<AltarikManifest>);
|
||||
|
||||
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
|
||||
#[tauri::command]
|
||||
fn greet(name: &str) -> String {
|
||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||
async fn login(app: tauri::AppHandle, _window: tauri::Window, state: tauri::State<'_, Mutex<CustomState>>) -> Result<String, String> {
|
||||
let result = Authentification::login(Prompt::SelectAccount, app).await;
|
||||
match result {
|
||||
Ok(val) => {
|
||||
let name = val.name.clone();
|
||||
match state.lock() {
|
||||
Ok(mut game_profile) => {
|
||||
game_profile.0 = Some(val);
|
||||
Ok(format!("Hello {}", name))
|
||||
},
|
||||
Err(err) => {
|
||||
Err(err.to_string())
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(err) => Err(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn login(app: tauri::AppHandle, _window: tauri::Window) -> Result<String, String> {
|
||||
let result = Authentification::login(Prompt::SelectAccount, app).await;
|
||||
match result {
|
||||
Ok(val) => Ok(format!("Hello {}", val.1)),
|
||||
Err(err) => Err(err.to_string())
|
||||
async fn load_altarik_manifest(state: tauri::State<'_, Mutex<CustomState>>) -> Result<AltarikManifest, String> {
|
||||
let reqwest_client = Client::new();
|
||||
let altarik_manifest = AltarikManifest::get_altarik_manifest(&reqwest_client).await;
|
||||
match altarik_manifest {
|
||||
Ok(val) => {
|
||||
match state.lock() {
|
||||
Ok(mut global_manifest) => {
|
||||
let _ = global_manifest.1.insert(val.clone());
|
||||
Ok(val)
|
||||
},
|
||||
Err(err) => {
|
||||
Err(err.to_string())
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
Err(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn download(selected_chapter: usize, app: tauri::AppHandle, state: tauri::State<'_, Mutex<CustomState>>) -> Result<String, String> {
|
||||
let chapter = match state.lock() {
|
||||
Ok(lock) => {
|
||||
match &lock.1 {
|
||||
Some(manifest) => {
|
||||
match manifest.chapters.get(selected_chapter) {
|
||||
Some(val) => {
|
||||
val.clone()
|
||||
},
|
||||
None => return Err("Selected chapter doesn't exist".to_string())
|
||||
}
|
||||
},
|
||||
None => return Err("Cannot load altarik manifest".to_string())
|
||||
}
|
||||
},
|
||||
Err(err) => return Err(err.to_string())
|
||||
};
|
||||
if let Some(base_dir) = BaseDirs::new() {
|
||||
let data_folder = base_dir.data_dir().join(".altarik_test");
|
||||
let root_path = data_folder.as_path();
|
||||
let java_path = root_path.join("java");
|
||||
let game_profile = match state.lock() {
|
||||
Ok(res) => Ok(res.0.clone()),
|
||||
Err(err) => Err(err.to_string())
|
||||
}?;
|
||||
if game_profile.is_none() {
|
||||
return Err("You're not connected".to_string());
|
||||
}
|
||||
let (sender, receiver) = mpsc::channel(60);
|
||||
let opts = ClientOptions {
|
||||
authorization: game_profile.unwrap(),
|
||||
log_channel: sender.clone(),
|
||||
root_path,
|
||||
java_path: &java_path.as_path(),
|
||||
version_number: chapter.minecraft_version.clone(),
|
||||
version_type: launcher::VersionType::Release,
|
||||
memory_min: "2G".to_string(),
|
||||
memory_max: "4G".to_string(),
|
||||
};
|
||||
drop(sender);
|
||||
let res = tokio::join!(
|
||||
download_libraries(opts, chapter),
|
||||
read_channel(receiver, app),
|
||||
);
|
||||
res.0
|
||||
} else {
|
||||
Err("Cannot download files".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async fn download_libraries(opts: ClientOptions<'_>, chapter: Chapter) -> Result<String, String> {
|
||||
let client = MinecraftClient::new(&opts, chapter).await;
|
||||
let res = match client {
|
||||
Ok(mut client) => {
|
||||
match client.download_requirements().await {
|
||||
Ok(_) => {
|
||||
Ok("Content downloaded".to_string())
|
||||
},
|
||||
Err(err) => {
|
||||
Err(err.to_string())
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
Err(err.to_string())
|
||||
}
|
||||
};
|
||||
res
|
||||
}
|
||||
|
||||
async fn read_channel(mut receiver: mpsc::Receiver<ProgressMessage>, app: tauri::AppHandle) -> Result<()> {
|
||||
loop {
|
||||
match receiver.recv().await {
|
||||
Some(msg) => { app.emit_all("progress", msg)? },
|
||||
None => break Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tauri::Builder::default()
|
||||
.invoke_handler(tauri::generate_handler![greet, login])
|
||||
.manage(Mutex::new(CustomState(None, None)))
|
||||
.invoke_handler(tauri::generate_handler![login, download, load_altarik_manifest])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "",
|
||||
"beforeBuildCommand": "",
|
||||
"devPath": "../src",
|
||||
"distDir": "../src",
|
||||
"withGlobalTauri": true
|
||||
"beforeDevCommand": "yarn dev",
|
||||
"beforeBuildCommand": "yarn build",
|
||||
"devPath": "http://localhost:1420",
|
||||
"distDir": "../dist",
|
||||
"withGlobalTauri": false
|
||||
},
|
||||
"package": {
|
||||
"productName": "Launcher-tauri",
|
||||
@ -12,16 +12,14 @@
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"all": true
|
||||
"all": false,
|
||||
"shell": {
|
||||
"all": false,
|
||||
"open": true
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"category": "DeveloperTool",
|
||||
"copyright": "",
|
||||
"deb": {
|
||||
"depends": []
|
||||
},
|
||||
"externalBin": [],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
@ -29,30 +27,12 @@
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"identifier": "com.tauri.dev",
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
"entitlements": null,
|
||||
"exceptionDomain": "",
|
||||
"frameworks": [],
|
||||
"providerShortName": null,
|
||||
"signingIdentity": null
|
||||
},
|
||||
"resources": [],
|
||||
"shortDescription": "",
|
||||
"targets": "all",
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": ""
|
||||
}
|
||||
"identifier": "fr.altarik.launcher",
|
||||
"targets": "all"
|
||||
},
|
||||
"security": {
|
||||
"csp": null
|
||||
},
|
||||
"updater": {
|
||||
"active": false
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"fullscreen": false,
|
||||
|
12
src/App.tsx
Normal file
12
src/App.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { invoke, event } from "@tauri-apps/api";
|
||||
import LoginPage from './components/LoginPage'
|
||||
|
||||
export default function App() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<LoginPage />
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
18
src/components/AltarikManifestComponent.tsx
Normal file
18
src/components/AltarikManifestComponent.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { AltarikManifest } from "../models/manifest/AltarikManifest";
|
||||
import ChapterList from "./ChapterList";
|
||||
|
||||
interface Props {
|
||||
manifest: AltarikManifest | undefined,
|
||||
selectedChapter: number,
|
||||
onClickFunction: Function
|
||||
}
|
||||
|
||||
export default function AltarikManifestComponent({manifest, selectedChapter, onClickFunction} : Props) {
|
||||
|
||||
return (
|
||||
<>
|
||||
{manifest != undefined ? <ChapterList chapters={manifest.chapters} selectedChapter={selectedChapter} onClickFunction={onClickFunction} /> : <></>}
|
||||
</>
|
||||
)
|
||||
|
||||
}
|
16
src/components/ChapterItem.tsx
Normal file
16
src/components/ChapterItem.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { title } from "process"
|
||||
import { Chapter } from "../models/manifest/AltarikManifest"
|
||||
import { MouseEventHandler } from "react"
|
||||
|
||||
interface Props {
|
||||
chapter: Chapter,
|
||||
isSelected: boolean,
|
||||
onClickFunction: MouseEventHandler<HTMLButtonElement>
|
||||
}
|
||||
|
||||
export default function ChapterItem({ chapter, isSelected, onClickFunction } : Props) {
|
||||
|
||||
return (
|
||||
<button className={isSelected ? "selected": ""} onClick={onClickFunction}>{chapter.title} -- {chapter.minecraftVersion}</button>
|
||||
)
|
||||
}
|
25
src/components/ChapterList.tsx
Normal file
25
src/components/ChapterList.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { AltarikManifest, Chapter } from "../models/manifest/AltarikManifest"
|
||||
import ChapterItem from "./ChapterItem"
|
||||
|
||||
|
||||
interface Props {
|
||||
chapters: Chapter[],
|
||||
selectedChapter: number,
|
||||
onClickFunction: Function
|
||||
}
|
||||
|
||||
|
||||
export default function ChapterList({ chapters, selectedChapter, onClickFunction }: Props) {
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div id="chaptersList">
|
||||
{
|
||||
chapters.map((chapter, key) => (
|
||||
<ChapterItem chapter={chapter} key={key} isSelected={key === selectedChapter} onClickFunction={() => onClickFunction(key)}/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
91
src/components/LoginPage.tsx
Normal file
91
src/components/LoginPage.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
import { useEffect, useState } from "react"
|
||||
import { invoke, event } from "@tauri-apps/api";
|
||||
import { AltarikManifest } from "../models/manifest/AltarikManifest";
|
||||
import AltarikManifestComponent from "./AltarikManifestComponent";
|
||||
|
||||
interface ProgressMessage {
|
||||
p_type: String,
|
||||
current: number,
|
||||
total: number
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default function LoginPage() {
|
||||
|
||||
const [greetMessage, setGreetMessage] = useState<String>("");
|
||||
const [isLogged, setIsLogged] = useState<boolean>(false);
|
||||
const [loginButtonDisabled, setLoginButtonDisabled] = useState<boolean>(false);
|
||||
const [altarikManifest, setAltarikManifest] = useState<AltarikManifest>();
|
||||
const [selectedChapter, setSelectChapter] = useState<number>(-1);
|
||||
|
||||
useEffect(() => {
|
||||
event.listen('progress', (e) => {
|
||||
let v = e.payload as ProgressMessage;
|
||||
setGreetMessage("{type: " + v.p_type + ", current: " + v.current + ", total: " + v.total + "}");
|
||||
// setGreetMessage(String(e.payload));
|
||||
});
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if(isLogged) {
|
||||
invoke('load_altarik_manifest', {}).then(val => {
|
||||
setAltarikManifest(val as AltarikManifest)
|
||||
}).catch(err => {
|
||||
setGreetMessage("Cannot load altarik manifest: " + err)
|
||||
})
|
||||
} else {
|
||||
setAltarikManifest(undefined)
|
||||
}
|
||||
}, [isLogged])
|
||||
|
||||
async function login () {
|
||||
if(!isLogged && !loginButtonDisabled) {
|
||||
setLoginButtonDisabled(true);
|
||||
invoke("login", {}).then(value => {
|
||||
setGreetMessage(String(value));
|
||||
setIsLogged(true);
|
||||
}).catch(err => {
|
||||
setGreetMessage("Error: " + err)
|
||||
setLoginButtonDisabled(false);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function download() {
|
||||
if(isLogged) {
|
||||
if(selectedChapter !== -1 && altarikManifest !== undefined) {
|
||||
invoke("download", { selectedChapter: selectedChapter }).then(value => {
|
||||
setGreetMessage(String(value))
|
||||
}).catch(err => {
|
||||
console.log("An error occured")
|
||||
setGreetMessage("Error: " + err)
|
||||
})
|
||||
} else {
|
||||
setGreetMessage("Please select a chapter first")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function select_chapter(key: number) {
|
||||
setSelectChapter(key)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Welcome to Tauri!</h1>
|
||||
<div className="row">
|
||||
<div>
|
||||
<button id="greet-button" type="button" onClick={login}>Login to minecraft</button>
|
||||
<button id="download-button" className={!isLogged ? "hide" : ""} onClick={download} v-on:click="download">Download game</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p id="greet-msg">{ greetMessage }</p>
|
||||
|
||||
<hr />
|
||||
<AltarikManifestComponent manifest={altarikManifest} selectedChapter={selectedChapter} onClickFunction={select_chapter} />
|
||||
</>
|
||||
)
|
||||
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
button_message: "Login to minecraft",
|
||||
greet_message: ""
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
login (e) {
|
||||
e.preventDefault()
|
||||
this.invoke("login", {}).then(value => {
|
||||
this.greet_message = value
|
||||
}).catch(err => {
|
||||
this.greet_message = "Error: " + err
|
||||
})
|
||||
}
|
||||
},
|
||||
props: {
|
||||
invoke: Object
|
||||
},
|
||||
template: `
|
||||
<h1>Welcome to Tauri!</h1>
|
||||
|
||||
<div class="row">
|
||||
<div>
|
||||
<button id="greet-button" type="button" v-on:click="login">{{ button_message }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p id="greet-msg">{{ greet_message }}</p>
|
||||
`
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
<loginpage :invoke="invoke"></loginpage>
|
||||
<loginpage :invoke="invoke" :listen="listen"></loginpage>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
19
src/main.js
19
src/main.js
@ -1,19 +0,0 @@
|
||||
const { invoke } = window.__TAURI__.tauri;
|
||||
|
||||
const { createApp } = Vue
|
||||
|
||||
import loginpage from './components/login.js'
|
||||
|
||||
createApp({
|
||||
data() {
|
||||
return {
|
||||
invoke: invoke
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
components: {
|
||||
loginpage
|
||||
}
|
||||
}).mount('#container')
|
10
src/main.tsx
Normal file
10
src/main.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App";
|
||||
import "./styles.css";
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
9
src/models/manifest/AltarikManifest.tsx
Normal file
9
src/models/manifest/AltarikManifest.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
export interface AltarikManifest {
|
||||
chapters: Chapter[]
|
||||
}
|
||||
|
||||
export interface Chapter {
|
||||
title: String,
|
||||
minecraftVersion: String,
|
||||
}
|
@ -84,6 +84,14 @@ button {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button.selected {
|
||||
color: red;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
color: #f6f6f6;
|
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
22
tsconfig.json
Normal file
22
tsconfig.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
|
10
tsconfig.node.json
Normal file
10
tsconfig.node.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
|
27
vite.config.ts
Normal file
27
vite.config.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(async () => ({
|
||||
plugins: [react()],
|
||||
|
||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||
// prevent vite from obscuring rust errors
|
||||
clearScreen: false,
|
||||
// tauri expects a fixed port, fail if that port is not available
|
||||
server: {
|
||||
port: 1420,
|
||||
strictPort: true,
|
||||
},
|
||||
// to make use of `TAURI_DEBUG` and other env variables
|
||||
// https://tauri.studio/v1/api/config#buildconfig.beforedevcommand
|
||||
envPrefix: ["VITE_", "TAURI_"],
|
||||
build: {
|
||||
// Tauri supports es2021
|
||||
target: process.env.TAURI_PLATFORM == "windows" ? "chrome105" : "safari13",
|
||||
// don't minify for debug builds
|
||||
minify: !process.env.TAURI_DEBUG ? "esbuild" : false,
|
||||
// produce sourcemaps for debug builds
|
||||
sourcemap: !!process.env.TAURI_DEBUG,
|
||||
},
|
||||
}));
|
749
yarn.lock
Normal file
749
yarn.lock
Normal file
@ -0,0 +1,749 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@ampproject/remapping@^2.2.0":
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630"
|
||||
integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==
|
||||
dependencies:
|
||||
"@jridgewell/gen-mapping" "^0.3.0"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@babel/code-frame@^7.22.13":
|
||||
version "7.22.13"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
|
||||
integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
|
||||
dependencies:
|
||||
"@babel/highlight" "^7.22.13"
|
||||
chalk "^2.4.2"
|
||||
|
||||
"@babel/compat-data@^7.22.9":
|
||||
version "7.22.20"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.20.tgz#8df6e96661209623f1975d66c35ffca66f3306d0"
|
||||
integrity sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==
|
||||
|
||||
"@babel/core@^7.20.12":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.0.tgz#f8259ae0e52a123eb40f552551e647b506a94d83"
|
||||
integrity sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==
|
||||
dependencies:
|
||||
"@ampproject/remapping" "^2.2.0"
|
||||
"@babel/code-frame" "^7.22.13"
|
||||
"@babel/generator" "^7.23.0"
|
||||
"@babel/helper-compilation-targets" "^7.22.15"
|
||||
"@babel/helper-module-transforms" "^7.23.0"
|
||||
"@babel/helpers" "^7.23.0"
|
||||
"@babel/parser" "^7.23.0"
|
||||
"@babel/template" "^7.22.15"
|
||||
"@babel/traverse" "^7.23.0"
|
||||
"@babel/types" "^7.23.0"
|
||||
convert-source-map "^2.0.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.2"
|
||||
json5 "^2.2.3"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/generator@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
|
||||
integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
|
||||
dependencies:
|
||||
"@babel/types" "^7.23.0"
|
||||
"@jridgewell/gen-mapping" "^0.3.2"
|
||||
"@jridgewell/trace-mapping" "^0.3.17"
|
||||
jsesc "^2.5.1"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.22.15":
|
||||
version "7.22.15"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52"
|
||||
integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.22.9"
|
||||
"@babel/helper-validator-option" "^7.22.15"
|
||||
browserslist "^4.21.9"
|
||||
lru-cache "^5.1.1"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-environment-visitor@^7.22.20":
|
||||
version "7.22.20"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
|
||||
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
|
||||
|
||||
"@babel/helper-function-name@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
|
||||
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
|
||||
dependencies:
|
||||
"@babel/template" "^7.22.15"
|
||||
"@babel/types" "^7.23.0"
|
||||
|
||||
"@babel/helper-hoist-variables@^7.22.5":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
|
||||
integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
|
||||
dependencies:
|
||||
"@babel/types" "^7.22.5"
|
||||
|
||||
"@babel/helper-module-imports@^7.22.15":
|
||||
version "7.22.15"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0"
|
||||
integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==
|
||||
dependencies:
|
||||
"@babel/types" "^7.22.15"
|
||||
|
||||
"@babel/helper-module-transforms@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e"
|
||||
integrity sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==
|
||||
dependencies:
|
||||
"@babel/helper-environment-visitor" "^7.22.20"
|
||||
"@babel/helper-module-imports" "^7.22.15"
|
||||
"@babel/helper-simple-access" "^7.22.5"
|
||||
"@babel/helper-split-export-declaration" "^7.22.6"
|
||||
"@babel/helper-validator-identifier" "^7.22.20"
|
||||
|
||||
"@babel/helper-plugin-utils@^7.22.5":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295"
|
||||
integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==
|
||||
|
||||
"@babel/helper-simple-access@^7.22.5":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de"
|
||||
integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==
|
||||
dependencies:
|
||||
"@babel/types" "^7.22.5"
|
||||
|
||||
"@babel/helper-split-export-declaration@^7.22.6":
|
||||
version "7.22.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
|
||||
integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
|
||||
dependencies:
|
||||
"@babel/types" "^7.22.5"
|
||||
|
||||
"@babel/helper-string-parser@^7.22.5":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
|
||||
integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.22.20":
|
||||
version "7.22.20"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
|
||||
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
|
||||
|
||||
"@babel/helper-validator-option@^7.22.15":
|
||||
version "7.22.15"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040"
|
||||
integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==
|
||||
|
||||
"@babel/helpers@^7.23.0":
|
||||
version "7.23.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.1.tgz#44e981e8ce2b9e99f8f0b703f3326a4636c16d15"
|
||||
integrity sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==
|
||||
dependencies:
|
||||
"@babel/template" "^7.22.15"
|
||||
"@babel/traverse" "^7.23.0"
|
||||
"@babel/types" "^7.23.0"
|
||||
|
||||
"@babel/highlight@^7.22.13":
|
||||
version "7.22.20"
|
||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
|
||||
integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.22.20"
|
||||
chalk "^2.4.2"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
|
||||
integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
|
||||
|
||||
"@babel/plugin-transform-react-jsx-self@^7.18.6":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz#ca2fdc11bc20d4d46de01137318b13d04e481d8e"
|
||||
integrity sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.22.5"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-source@^7.19.6":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz#49af1615bfdf6ed9d3e9e43e425e0b2b65d15b6c"
|
||||
integrity sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.22.5"
|
||||
|
||||
"@babel/template@^7.22.15":
|
||||
version "7.22.15"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
|
||||
integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.22.13"
|
||||
"@babel/parser" "^7.22.15"
|
||||
"@babel/types" "^7.22.15"
|
||||
|
||||
"@babel/traverse@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.0.tgz#18196ddfbcf4ccea324b7f6d3ada00d8c5a99c53"
|
||||
integrity sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.22.13"
|
||||
"@babel/generator" "^7.23.0"
|
||||
"@babel/helper-environment-visitor" "^7.22.20"
|
||||
"@babel/helper-function-name" "^7.23.0"
|
||||
"@babel/helper-hoist-variables" "^7.22.5"
|
||||
"@babel/helper-split-export-declaration" "^7.22.6"
|
||||
"@babel/parser" "^7.23.0"
|
||||
"@babel/types" "^7.23.0"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
|
||||
integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.22.5"
|
||||
"@babel/helper-validator-identifier" "^7.22.20"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@esbuild/android-arm64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622"
|
||||
integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==
|
||||
|
||||
"@esbuild/android-arm@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682"
|
||||
integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==
|
||||
|
||||
"@esbuild/android-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2"
|
||||
integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==
|
||||
|
||||
"@esbuild/darwin-arm64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1"
|
||||
integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==
|
||||
|
||||
"@esbuild/darwin-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d"
|
||||
integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==
|
||||
|
||||
"@esbuild/freebsd-arm64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54"
|
||||
integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==
|
||||
|
||||
"@esbuild/freebsd-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e"
|
||||
integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==
|
||||
|
||||
"@esbuild/linux-arm64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0"
|
||||
integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==
|
||||
|
||||
"@esbuild/linux-arm@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0"
|
||||
integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==
|
||||
|
||||
"@esbuild/linux-ia32@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7"
|
||||
integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==
|
||||
|
||||
"@esbuild/linux-loong64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d"
|
||||
integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==
|
||||
|
||||
"@esbuild/linux-mips64el@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231"
|
||||
integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==
|
||||
|
||||
"@esbuild/linux-ppc64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb"
|
||||
integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==
|
||||
|
||||
"@esbuild/linux-riscv64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6"
|
||||
integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==
|
||||
|
||||
"@esbuild/linux-s390x@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071"
|
||||
integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==
|
||||
|
||||
"@esbuild/linux-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338"
|
||||
integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==
|
||||
|
||||
"@esbuild/netbsd-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1"
|
||||
integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==
|
||||
|
||||
"@esbuild/openbsd-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae"
|
||||
integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==
|
||||
|
||||
"@esbuild/sunos-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d"
|
||||
integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==
|
||||
|
||||
"@esbuild/win32-arm64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9"
|
||||
integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==
|
||||
|
||||
"@esbuild/win32-ia32@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102"
|
||||
integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==
|
||||
|
||||
"@esbuild/win32-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d"
|
||||
integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==
|
||||
|
||||
"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2":
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098"
|
||||
integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==
|
||||
dependencies:
|
||||
"@jridgewell/set-array" "^1.0.1"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@jridgewell/resolve-uri@^3.1.0":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
|
||||
integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
|
||||
|
||||
"@jridgewell/set-array@^1.0.1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
|
||||
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.14":
|
||||
version "1.4.15"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
|
||||
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9":
|
||||
version "0.3.19"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811"
|
||||
integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri" "^3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||
|
||||
"@tauri-apps/api@^1.4.0":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/api/-/api-1.5.0.tgz#46a0f9b6edd4bfc39be32afc4ad242e0b8cca3ea"
|
||||
integrity sha512-yQY9wpVNuiYhLLuyDlu1nBpqJELT1fGp7OctN4rW9I2W1T2p7A3tqPxsEzQprEwneQRBAlPM9vC8NsnMbct+pg==
|
||||
|
||||
"@tauri-apps/cli-darwin-arm64@1.5.1":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.5.1.tgz#d2e046c9bf54e77d47debf6ccf226c6d5b44e529"
|
||||
integrity sha512-o2FSGj72gqJjlVtuScXQZUgiRs90PS9gG7YAz0Hgr4nV1MfIn9U6JVj6R+mnAEZBCK8qdy5jdemhmNKDDoiYQg==
|
||||
|
||||
"@tauri-apps/cli-darwin-x64@1.5.1":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.5.1.tgz#9c513499a65af2ed07945921a7e5656973b3cf4c"
|
||||
integrity sha512-G1/v6AJPP5oIcjsOxZshag28wdmDx1Fis2yz545aUk7oKU86A3ZJpz0b8BaXkr93w04xGcmGAaspZeXMmTvrbw==
|
||||
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf@1.5.1":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.5.1.tgz#1b9088a3fd1e7f98e571ae4ac64cce36bc32ec8e"
|
||||
integrity sha512-hPDOUMviffyX5BySk6RuD7IZZeMuNUJzKWHxVWa0NHJPfxQOIPWwYWbk6TascrVk9GZYAImcB0yKfrll8I0VTg==
|
||||
|
||||
"@tauri-apps/cli-linux-arm64-gnu@1.5.1":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.5.1.tgz#93ae5f4231c61f6645630e338b761a38056b73ca"
|
||||
integrity sha512-EJjTXqZchFLVrFgfxwstrQj7NwVDirffLhw5hRWS3L3Iys3IvqzIMVIA+GrY7KsaPwq7qaSqE1CDtP1wejE/9g==
|
||||
|
||||
"@tauri-apps/cli-linux-arm64-musl@1.5.1":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.5.1.tgz#fb1d6848ed24f9416fbec62d8a2603aa4bd94595"
|
||||
integrity sha512-XgJIk0AcxRL4pWVjfj0wiC9WnIZoUIVLPcQs86dNxoqzwAvADdNYp+McXf3/MDxX8uGEzpgdvlqr4T+50c8f6w==
|
||||
|
||||
"@tauri-apps/cli-linux-x64-gnu@1.5.1":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.5.1.tgz#ff9e05828b707017caef2934c8a292cac979eeca"
|
||||
integrity sha512-VoVrIn7b+F2n0LJoDkLGXQJsPV/U1h3QnjRNE+Tcju6xVPBx64H0vfb7lC3S4QfVpiQ4Uc+1UD3Slvn4jGpL/A==
|
||||
|
||||
"@tauri-apps/cli-linux-x64-musl@1.5.1":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.5.1.tgz#6cec6f33c35f927703bf0b17585e4604872d9105"
|
||||
integrity sha512-tQi2K0LYW80BLud7ZFOy3WxCM2VjDRxuhxOYhtcLG39cIeGqsSz07LwiCFNBn4vy2J47TnZ+8XDRAOtxSFe25w==
|
||||
|
||||
"@tauri-apps/cli-win32-arm64-msvc@1.5.1":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.5.1.tgz#0315fd57efa6a54f9cb0144946dc626edc378acf"
|
||||
integrity sha512-BdVwzVXY2JWBtWEO/G0//jIWXeWR52+KG0+kyoHO6QTxkncLrN5q2RldvXOe7CvhKe/qmgbkNosj5jWi7t49kQ==
|
||||
|
||||
"@tauri-apps/cli-win32-ia32-msvc@1.5.1":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.5.1.tgz#c3508bc8d4eb6d95becca02809d6bcbdd05d3d25"
|
||||
integrity sha512-Q0ei4ZUHlGu/b4DP4Cm6WnI5zxpLxnf/vSwR2BYO3XO65TdLee1gTyuwYuSZJYu5jxqSoSusmLyL4F43jHhf9Q==
|
||||
|
||||
"@tauri-apps/cli-win32-x64-msvc@1.5.1":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.5.1.tgz#04f4af26589708752d711bfd1ef4dca21e2b3f7c"
|
||||
integrity sha512-chpsJ5PIwMOdn1IIJ6bj2G7jv9jQryVvhujU0k3kt/5kE7OuLRDYbI5BAIzMOaLoOTgoo8oxcFXQ+enELSxlMQ==
|
||||
|
||||
"@tauri-apps/cli@^1.4.0":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli/-/cli-1.5.1.tgz#2aba9b320f1b79f160e7c011110ae5d2b25a8de2"
|
||||
integrity sha512-Ssj30axil5vPBV3W5ScHXk4umTKu6BhfmMdljfKDOG9K55gAqzBAE2VBC5e/ouclSxZfN+6YNL9VhDXFu/UyeA==
|
||||
optionalDependencies:
|
||||
"@tauri-apps/cli-darwin-arm64" "1.5.1"
|
||||
"@tauri-apps/cli-darwin-x64" "1.5.1"
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf" "1.5.1"
|
||||
"@tauri-apps/cli-linux-arm64-gnu" "1.5.1"
|
||||
"@tauri-apps/cli-linux-arm64-musl" "1.5.1"
|
||||
"@tauri-apps/cli-linux-x64-gnu" "1.5.1"
|
||||
"@tauri-apps/cli-linux-x64-musl" "1.5.1"
|
||||
"@tauri-apps/cli-win32-arm64-msvc" "1.5.1"
|
||||
"@tauri-apps/cli-win32-ia32-msvc" "1.5.1"
|
||||
"@tauri-apps/cli-win32-x64-msvc" "1.5.1"
|
||||
|
||||
"@types/node@^18.7.10":
|
||||
version "18.18.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.3.tgz#e5188135fc2909b46530c798ef49be65083be3fd"
|
||||
integrity sha512-0OVfGupTl3NBFr8+iXpfZ8NR7jfFO+P1Q+IO/q0wbo02wYkP5gy36phojeYWpLQ6WAMjl+VfmqUk2YbUfp0irA==
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.8.tgz#805eae6e8f41bd19e88917d2ea200dc992f405d3"
|
||||
integrity sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ==
|
||||
|
||||
"@types/react-dom@^18.0.6":
|
||||
version "18.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.10.tgz#06247cb600e39b63a0a385f6a5014c44bab296f2"
|
||||
integrity sha512-5VEC5RgXIk1HHdyN1pHlg0cOqnxHzvPGpMMyGAP5qSaDRmyZNDaQ0kkVAkK6NYlDhP6YBID3llaXlmAS/mdgCA==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^18.0.15":
|
||||
version "18.2.25"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.25.tgz#99fa44154132979e870ff409dc5b6e67f06f0199"
|
||||
integrity sha512-24xqse6+VByVLIr+xWaQ9muX1B4bXJKXBbjszbld/UEDslGLY53+ZucF44HCmLbMPejTzGG9XgR+3m2/Wqu1kw==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/scheduler@*":
|
||||
version "0.16.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.4.tgz#fedc3e5b15c26dc18faae96bf1317487cb3658cf"
|
||||
integrity sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ==
|
||||
|
||||
"@vitejs/plugin-react@^3.0.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-3.1.0.tgz#d1091f535eab8b83d6e74034d01e27d73c773240"
|
||||
integrity sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==
|
||||
dependencies:
|
||||
"@babel/core" "^7.20.12"
|
||||
"@babel/plugin-transform-react-jsx-self" "^7.18.6"
|
||||
"@babel/plugin-transform-react-jsx-source" "^7.19.6"
|
||||
magic-string "^0.27.0"
|
||||
react-refresh "^0.14.0"
|
||||
|
||||
"@welldone-software/why-did-you-render@^7.0.1":
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@welldone-software/why-did-you-render/-/why-did-you-render-7.0.1.tgz#09f487d84844bd8e66435843c2e0305702e61efb"
|
||||
integrity sha512-Qe/8Xxa2G+LMdI6VoazescPzjjkHYduCDa8aHOJR50e9Bgs8ihkfMBY+ev7B4oc3N59Zm547Sgjf8h5y0FOyoA==
|
||||
dependencies:
|
||||
lodash "^4"
|
||||
|
||||
ansi-styles@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
||||
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
|
||||
dependencies:
|
||||
color-convert "^1.9.0"
|
||||
|
||||
browserslist@^4.21.9:
|
||||
version "4.22.1"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619"
|
||||
integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==
|
||||
dependencies:
|
||||
caniuse-lite "^1.0.30001541"
|
||||
electron-to-chromium "^1.4.535"
|
||||
node-releases "^2.0.13"
|
||||
update-browserslist-db "^1.0.13"
|
||||
|
||||
caniuse-lite@^1.0.30001541:
|
||||
version "1.0.30001543"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001543.tgz#478a3e9dddbb353c5ab214b0ecb0dbed529ed1d8"
|
||||
integrity sha512-qxdO8KPWPQ+Zk6bvNpPeQIOH47qZSYdFZd6dXQzb2KzhnSXju4Kd7H1PkSJx6NICSMgo/IhRZRhhfPTHYpJUCA==
|
||||
|
||||
chalk@^2.4.2:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
dependencies:
|
||||
ansi-styles "^3.2.1"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
color-convert@^1.9.0:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
||||
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
|
||||
dependencies:
|
||||
color-name "1.1.3"
|
||||
|
||||
color-name@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||
|
||||
convert-source-map@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
|
||||
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
|
||||
|
||||
csstype@^3.0.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
|
||||
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
|
||||
|
||||
debug@^4.1.0:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
electron-to-chromium@^1.4.535:
|
||||
version "1.4.540"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.540.tgz#c685f2f035e93eb21dd6a9cfe2c735bad8f77401"
|
||||
integrity sha512-aoCqgU6r9+o9/S7wkcSbmPRFi7OWZWiXS9rtjEd+Ouyu/Xyw5RSq2XN8s5Qp8IaFOLiRrhQCphCIjAxgG3eCAg==
|
||||
|
||||
esbuild@^0.18.10:
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6"
|
||||
integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==
|
||||
optionalDependencies:
|
||||
"@esbuild/android-arm" "0.18.20"
|
||||
"@esbuild/android-arm64" "0.18.20"
|
||||
"@esbuild/android-x64" "0.18.20"
|
||||
"@esbuild/darwin-arm64" "0.18.20"
|
||||
"@esbuild/darwin-x64" "0.18.20"
|
||||
"@esbuild/freebsd-arm64" "0.18.20"
|
||||
"@esbuild/freebsd-x64" "0.18.20"
|
||||
"@esbuild/linux-arm" "0.18.20"
|
||||
"@esbuild/linux-arm64" "0.18.20"
|
||||
"@esbuild/linux-ia32" "0.18.20"
|
||||
"@esbuild/linux-loong64" "0.18.20"
|
||||
"@esbuild/linux-mips64el" "0.18.20"
|
||||
"@esbuild/linux-ppc64" "0.18.20"
|
||||
"@esbuild/linux-riscv64" "0.18.20"
|
||||
"@esbuild/linux-s390x" "0.18.20"
|
||||
"@esbuild/linux-x64" "0.18.20"
|
||||
"@esbuild/netbsd-x64" "0.18.20"
|
||||
"@esbuild/openbsd-x64" "0.18.20"
|
||||
"@esbuild/sunos-x64" "0.18.20"
|
||||
"@esbuild/win32-arm64" "0.18.20"
|
||||
"@esbuild/win32-ia32" "0.18.20"
|
||||
"@esbuild/win32-x64" "0.18.20"
|
||||
|
||||
escalade@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
||||
|
||||
escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
|
||||
|
||||
fsevents@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
|
||||
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
||||
|
||||
gensync@^1.0.0-beta.2:
|
||||
version "1.0.0-beta.2"
|
||||
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
|
||||
|
||||
globals@^11.1.0:
|
||||
version "11.12.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
|
||||
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
|
||||
|
||||
has-flag@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||
integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
|
||||
|
||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||
|
||||
jsesc@^2.5.1:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
|
||||
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
|
||||
|
||||
json5@^2.2.3:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
|
||||
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
|
||||
|
||||
lodash@^4:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
||||
loose-envify@^1.1.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
dependencies:
|
||||
js-tokens "^3.0.0 || ^4.0.0"
|
||||
|
||||
lru-cache@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
||||
integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
|
||||
dependencies:
|
||||
yallist "^3.0.2"
|
||||
|
||||
magic-string@^0.27.0:
|
||||
version "0.27.0"
|
||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3"
|
||||
integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==
|
||||
dependencies:
|
||||
"@jridgewell/sourcemap-codec" "^1.4.13"
|
||||
|
||||
ms@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
nanoid@^3.3.6:
|
||||
version "3.3.6"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
|
||||
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
|
||||
|
||||
node-releases@^2.0.13:
|
||||
version "2.0.13"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d"
|
||||
integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==
|
||||
|
||||
picocolors@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
||||
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
||||
|
||||
postcss@^8.4.27:
|
||||
version "8.4.31"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
|
||||
integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
|
||||
dependencies:
|
||||
nanoid "^3.3.6"
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
react-dom@^18.2.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
|
||||
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
scheduler "^0.23.0"
|
||||
|
||||
react-refresh@^0.14.0:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
|
||||
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
|
||||
|
||||
react@^18.2.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
|
||||
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
|
||||
rollup@^3.27.1:
|
||||
version "3.29.4"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981"
|
||||
integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
scheduler@^0.23.0:
|
||||
version "0.23.0"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
|
||||
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
|
||||
semver@^6.3.1:
|
||||
version "6.3.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||
|
||||
source-map-js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||
integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
|
||||
|
||||
typescript@^4.9.5:
|
||||
version "4.9.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
|
||||
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
|
||||
|
||||
update-browserslist-db@^1.0.13:
|
||||
version "1.0.13"
|
||||
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4"
|
||||
integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==
|
||||
dependencies:
|
||||
escalade "^3.1.1"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
vite@^4.2.1:
|
||||
version "4.4.10"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.10.tgz#3794639cc433f7cb33ad286930bf0378c86261c8"
|
||||
integrity sha512-TzIjiqx9BEXF8yzYdF2NTf1kFFbjMjUSV0LFZ3HyHoI3SGSPLnnFUKiIQtL3gl2AjHvMrprOvQ3amzaHgQlAxw==
|
||||
dependencies:
|
||||
esbuild "^0.18.10"
|
||||
postcss "^8.4.27"
|
||||
rollup "^3.27.1"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
yallist@^3.0.2:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
|
Reference in New Issue
Block a user