Compare commits
103 Commits
feature/sc
...
a0bfeddeba
Author | SHA1 | Date | |
---|---|---|---|
a0bfeddeba | |||
2b3b4bc38c | |||
50e9394961 | |||
103b26c6ad | |||
480b6ae220 | |||
482893c4a3 | |||
0cee1860b4 | |||
cee9bb5879 | |||
e5b72484ad | |||
96c4ffface | |||
a1aef0ce4c | |||
157ec7ac1a | |||
f5fde5d87a | |||
781063c813 | |||
c8ff0de4e7 | |||
86edbb571e | |||
86264e3f83 | |||
2b67704175 | |||
e307d3c5ba | |||
3db5a22d74 | |||
f1ff03045d | |||
f6d816f224 | |||
ed110d3b4a | |||
a034578c0f | |||
644c169d44 | |||
47a3f27f8a | |||
123b7daccc | |||
29b371f20e | |||
c3a0c5355d | |||
0d313f846b | |||
e996c59934 | |||
8cbcbaf373 | |||
3882dae5ec | |||
c2763c6429 | |||
334243f1e4 | |||
6ae00a1d3a | |||
a245b98e32 | |||
734b5fd91f | |||
7d0fc29984 | |||
00c486c40d | |||
7b102fc1a5 | |||
ff3260c08b | |||
4ac34bca6f | |||
51800eb11f | |||
9596d0859c | |||
03c79d5190 | |||
dc446ec217 | |||
e4b4293f2b | |||
74ea9ddf79
|
|||
ec8d0b5ebc
|
|||
15dd5ce45e
|
|||
13321a44a2 | |||
24b9ab97b5 | |||
39416042ba | |||
5d7539b72d | |||
1953a5b467 | |||
22e8466e3b | |||
82eb9894d7 | |||
a843fbfa04 | |||
95007ee15b | |||
49ea2bb3a4 | |||
b20574bf6c | |||
650a3b05c2 | |||
15a72ace70 | |||
86dd72b71a | |||
bbb037ee71 | |||
1e824b0692 | |||
7e18f95026 | |||
989ca5df21 | |||
f571c724dc | |||
82e9bec7c9 | |||
aa992b7e3e | |||
3c77241c93 | |||
a7ca61a086 | |||
484d5b4119 | |||
9a15b512fc | |||
02dbc498ae | |||
1275ac07fd | |||
a1e9f31dc2 | |||
34e009e53c | |||
a3a10e7f35 | |||
8fca3e147f | |||
120a1ae223 | |||
cbaa6b9e8d | |||
502bb26b90 | |||
bf7675d20b | |||
edce6fa0ac | |||
2cf4169542 | |||
44b0f32a9b | |||
c18db07cba | |||
4df964f023
|
|||
adab603511 | |||
b70cf5e25d | |||
11f02eba00 | |||
5f90d663cf
|
|||
ea61ba9ed7
|
|||
86cc2ea889
|
|||
5aecf1ef26
|
|||
085fc3b179
|
|||
66358bdd05
|
|||
2608b10efa
|
|||
92ce57dc60
|
|||
05745f51ad |
4
.dockerignore
Normal file
4
.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
||||
target/
|
||||
.git/
|
||||
.env
|
||||
data/
|
2
.drone.yml
Normal file
2
.drone.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
kind: template
|
||||
load: cuddle-rust-service-plan.yaml
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
target/
|
||||
.env
|
||||
|
2018
Cargo.lock
generated
2018
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,2 @@
|
||||
[workspace]
|
||||
|
||||
members = ["src/cmd/scel", "src/lib/scel_core", "src/lib/scel_api"]
|
||||
members = ["crates/*"]
|
||||
|
31
Dockerfile
Normal file
31
Dockerfile
Normal file
@@ -0,0 +1,31 @@
|
||||
FROM node:22-alpine as web_builder
|
||||
|
||||
WORKDIR /usr/src/scel/web
|
||||
|
||||
COPY src/web/ .
|
||||
|
||||
RUN --mount=type=cache,target=/usr/src/scel/web/dist yarn
|
||||
RUN --mount=type=cache,target=/usr/src/scel/web/dist yarn build
|
||||
|
||||
FROM rust:1.88 as builder
|
||||
|
||||
WORKDIR /usr/src/scel
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN --mount=type=cache,target=/usr/src/scel/target cargo build --release
|
||||
RUN --mount=type=cache,target=/usr/src/scel/target cargo install --path src/cmd/scel
|
||||
|
||||
FROM debian:bullseye-slim
|
||||
|
||||
# Install YTD
|
||||
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
|
||||
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \
|
||||
apt-get update && apt-get install -y python3 python3-pip
|
||||
RUN python3 -m pip install -U yt-dlp
|
||||
|
||||
# Copy binary
|
||||
COPY --from=builder /usr/local/cargo/bin/scel /usr/local/bin/scel
|
||||
COPY --from=web_builder /usr/src/scel/web/dist /src/web/dist
|
||||
|
||||
CMD ["scel"]
|
@@ -6,10 +6,11 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
tokio = { version = "1.22", features = ["full"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
anyhow = { version = "1.0.58" }
|
||||
anyhow = { version = "1.0.66" }
|
||||
dotenv = { version = "*" }
|
||||
|
||||
scel_api = { path = "../../lib/scel_api" }
|
||||
scel_core = { path = "../../lib/scel_core" }
|
||||
scel_api = { path = "../scel_api" }
|
||||
scel_core = { path = "../scel_core" }
|
28
crates/scel/src/main.rs
Normal file
28
crates/scel/src/main.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use dotenv::dotenv;
|
||||
use scel_core::App;
|
||||
use tracing::info;
|
||||
use tracing_subscriber::{EnvFilter, FmtSubscriber};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
dotenv().ok();
|
||||
|
||||
let subscriber = FmtSubscriber::builder()
|
||||
.with_env_filter(
|
||||
EnvFilter::default()
|
||||
.add_directive("tower_http=debug".parse().unwrap())
|
||||
.add_directive("scel_api=info".parse().unwrap())
|
||||
.add_directive("scel=info".parse().unwrap()),
|
||||
)
|
||||
.finish();
|
||||
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
|
||||
info!("Starting scel");
|
||||
|
||||
let app = Arc::new(App::new());
|
||||
|
||||
scel_api::Server::new(app.clone()).start().await
|
||||
}
|
33
crates/scel_api/Cargo.toml
Normal file
33
crates/scel_api/Cargo.toml
Normal file
@@ -0,0 +1,33 @@
|
||||
[package]
|
||||
name = "scel_api"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
axum = { version = "0.5.17" }
|
||||
axum-extra = { version = "0.3.7", features = ["spa"] }
|
||||
futures = "0.3.30"
|
||||
tower-http = { version = "0.6.0", features = ["cors", "trace"] }
|
||||
async-graphql = { version = "7.0.0", features = [
|
||||
'tracing',
|
||||
'opentelemetry',
|
||||
"log",
|
||||
] }
|
||||
async-graphql-axum = { version = "7.0.0" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0.89"
|
||||
tokio = { version = "1.22", features = ["full"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3" }
|
||||
anyhow = { version = "1.0.66" }
|
||||
oauth2 = { version = "*" }
|
||||
async-session = { version = "*" }
|
||||
reqwest = { version = "*", default-features = false, features = [
|
||||
"rustls-tls",
|
||||
"json",
|
||||
] }
|
||||
hyper = { version = "*" }
|
||||
|
||||
scel_core = { path = "../scel_core" }
|
99
crates/scel_api/src/auth/mod.rs
Normal file
99
crates/scel_api/src/auth/mod.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
use std::env;
|
||||
|
||||
use async_session::{MemoryStore, Session, SessionStore};
|
||||
use axum::{
|
||||
extract::Query,
|
||||
http::HeaderMap,
|
||||
response::{IntoResponse, Redirect},
|
||||
Extension,
|
||||
};
|
||||
use oauth2::{
|
||||
basic::BasicClient, reqwest::async_http_client, AuthUrl, AuthorizationCode, ClientId,
|
||||
ClientSecret, CsrfToken, RedirectUrl, TokenResponse, TokenUrl,
|
||||
};
|
||||
use reqwest::header::SET_COOKIE;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{User, COOKIE_NAME};
|
||||
|
||||
pub fn oauth_client() -> BasicClient {
|
||||
let client_id = env::var("GITEA_CLIENT_ID").expect("Missing GITEA_CLIENT_ID");
|
||||
let client_secret = env::var("GITEA_CLIENT_SECRET").expect("Missing GITEA_CLIENT_SECRET");
|
||||
let redirect_url = env::var("GITEA_REDIRECT_URL")
|
||||
.unwrap_or_else(|_| "http://127.0.0.1:3000/auth/authorized".to_string());
|
||||
|
||||
let auth_url =
|
||||
env::var("GITEA_AUTH_URL").unwrap_or_else(|_| "https://git.front.kjuulh.io".to_string());
|
||||
|
||||
let token_url =
|
||||
env::var("GITEA_TOKEN_URL").unwrap_or_else(|_| "https://git.front.kjuulh.io".to_string());
|
||||
|
||||
BasicClient::new(
|
||||
ClientId::new(client_id),
|
||||
Some(ClientSecret::new(client_secret)),
|
||||
AuthUrl::new(auth_url).expect("AuthUrl was invalid"),
|
||||
Some(TokenUrl::new(token_url).expect("Token url was invalid")),
|
||||
)
|
||||
.set_redirect_uri(RedirectUrl::new(redirect_url).expect("RedirectUrl was invalid"))
|
||||
}
|
||||
|
||||
pub async fn gitea(Extension(client): Extension<BasicClient>) -> impl IntoResponse {
|
||||
let (auth_url, _crsf_token) = client.authorize_url(CsrfToken::new_random).url();
|
||||
|
||||
Redirect::to(&auth_url.to_string())
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AuthRequest {
|
||||
code: String,
|
||||
state: String,
|
||||
}
|
||||
|
||||
pub async fn authorized(
|
||||
Query(query): Query<AuthRequest>,
|
||||
Extension(store): Extension<MemoryStore>,
|
||||
Extension(oauth_client): Extension<BasicClient>,
|
||||
) -> impl IntoResponse {
|
||||
let token = oauth_client
|
||||
.exchange_code(AuthorizationCode::new(query.code.clone()))
|
||||
.request_async(async_http_client)
|
||||
.await
|
||||
.expect("failed to get http client");
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let user_data_json = client
|
||||
.get(get_gitea_user_data_url())
|
||||
.bearer_auth(token.access_token().secret())
|
||||
.send()
|
||||
.await
|
||||
.expect("Request did not succeed");
|
||||
// .text()
|
||||
// .await
|
||||
// .unwrap();
|
||||
|
||||
let user_data: User = user_data_json
|
||||
.json::<User>()
|
||||
.await
|
||||
.expect("could not parse user");
|
||||
|
||||
let mut session = Session::new();
|
||||
session
|
||||
.insert("user", &user_data)
|
||||
.expect("could not insert user data");
|
||||
|
||||
let cookie = store
|
||||
.store_session(session)
|
||||
.await
|
||||
.expect("could not insert session")
|
||||
.expect("session was not valid");
|
||||
|
||||
let cookie = format!("{}={}; SameSite=Lax; Path=/", COOKIE_NAME, cookie);
|
||||
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(SET_COOKIE, cookie.parse().expect("Cookie is not valid"));
|
||||
(headers, Redirect::to("/"))
|
||||
}
|
||||
|
||||
fn get_gitea_user_data_url() -> String {
|
||||
env::var("GITEA_USER_INFO_URL").expect("Missing GITEA_USER_INFO_URL")
|
||||
}
|
4
crates/scel_api/src/graphql/mod.rs
Normal file
4
crates/scel_api/src/graphql/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod mutation;
|
||||
pub mod query;
|
||||
pub mod schema;
|
||||
pub mod subscription;
|
38
crates/scel_api/src/graphql/mutation.rs
Normal file
38
crates/scel_api/src/graphql/mutation.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_graphql::{Context, Object, Result, SimpleObject, ID};
|
||||
use scel_core::{services::Download, App};
|
||||
|
||||
pub struct MutationRoot;
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
struct RequestDownloadResponse {
|
||||
id: ID,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl MutationRoot {
|
||||
async fn request_download(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
download_link: String,
|
||||
) -> Result<RequestDownloadResponse> {
|
||||
let app = ctx.data_unchecked::<Arc<App>>();
|
||||
|
||||
let download = app
|
||||
.download_service
|
||||
.clone()
|
||||
.add_download(Download {
|
||||
id: None,
|
||||
link: download_link,
|
||||
progress: None,
|
||||
file_name: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Ok(RequestDownloadResponse {
|
||||
id: download.id.unwrap().into(),
|
||||
})
|
||||
}
|
||||
}
|
32
crates/scel_api/src/graphql/query.rs
Normal file
32
crates/scel_api/src/graphql/query.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_graphql::{Context, Object, Result, SimpleObject, ID};
|
||||
use scel_core::App;
|
||||
|
||||
#[derive(SimpleObject, Clone)]
|
||||
pub struct Download {
|
||||
pub id: ID,
|
||||
pub link: String,
|
||||
pub progress: Option<u32>,
|
||||
pub file_name: Option<String>,
|
||||
}
|
||||
|
||||
pub struct QueryRoot;
|
||||
|
||||
#[Object]
|
||||
impl QueryRoot {
|
||||
async fn get_download(&self, ctx: &Context<'_>, id: ID) -> Result<Option<Download>> {
|
||||
let app = ctx.data_unchecked::<Arc<App>>();
|
||||
|
||||
match app.download_service.get_download(id.to_string()).await {
|
||||
Ok(Some(d)) => Ok(Some(Download {
|
||||
id: ID::from(d.id.expect("ID could not be found")),
|
||||
progress: None,
|
||||
link: d.link,
|
||||
file_name: None,
|
||||
})),
|
||||
Ok(None) => Ok(None),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
use async_graphql::Schema;
|
||||
|
||||
use crate::{mutation::MutationRoot, query::QueryRoot, subscription::SubscriptionRoot};
|
||||
use super::{mutation::MutationRoot, query::QueryRoot, subscription::SubscriptionRoot};
|
||||
|
||||
pub type ScelSchema = Schema<QueryRoot, MutationRoot, SubscriptionRoot>;
|
49
crates/scel_api/src/graphql/subscription.rs
Normal file
49
crates/scel_api/src/graphql/subscription.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_graphql::{
|
||||
async_stream::stream, futures_util::Stream, Context, Object, Subscription, ID,
|
||||
};
|
||||
use scel_core::App;
|
||||
|
||||
use super::query::Download;
|
||||
|
||||
pub struct SubscriptionRoot;
|
||||
|
||||
struct DownloadChanged {
|
||||
download: Download,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl DownloadChanged {
|
||||
async fn download(&self) -> Download {
|
||||
self.download.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[Subscription]
|
||||
impl SubscriptionRoot {
|
||||
async fn get_download(&self, ctx: &Context<'_>, id: ID) -> impl Stream<Item = DownloadChanged> {
|
||||
let app = ctx.data_unchecked::<Arc<App>>();
|
||||
|
||||
let mut stream = app
|
||||
.download_service
|
||||
.subscribe_download(id.to_string())
|
||||
.await;
|
||||
|
||||
stream! {
|
||||
while stream.changed().await.is_ok() {
|
||||
let next_download = (*stream.borrow()).clone();
|
||||
let id = ID::from(next_download.id.unwrap());
|
||||
|
||||
yield DownloadChanged {
|
||||
download: Download {
|
||||
id: id,
|
||||
link: next_download.link,
|
||||
file_name: next_download.file_name,
|
||||
progress: next_download.progress,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
173
crates/scel_api/src/lib.rs
Normal file
173
crates/scel_api/src/lib.rs
Normal file
@@ -0,0 +1,173 @@
|
||||
mod auth;
|
||||
mod graphql;
|
||||
|
||||
use std::{io, net::SocketAddr, sync::Arc};
|
||||
|
||||
use async_graphql::{
|
||||
extensions::{Logger, Tracing},
|
||||
http::{playground_source, GraphQLPlaygroundConfig},
|
||||
Request, Response, Schema,
|
||||
};
|
||||
use async_graphql_axum::GraphQLSubscription;
|
||||
use async_session::{async_trait, MemoryStore, SessionStore};
|
||||
use auth::{authorized, gitea};
|
||||
use axum::{
|
||||
extract::{rejection::TypedHeaderRejectionReason, FromRequest, RequestParts},
|
||||
headers,
|
||||
http::{header, Method},
|
||||
response::{Html, IntoResponse, Redirect},
|
||||
routing::{self, get_service},
|
||||
Extension, Json, Router, TypedHeader,
|
||||
};
|
||||
use graphql::{
|
||||
mutation::MutationRoot, query::QueryRoot, schema::ScelSchema, subscription::SubscriptionRoot,
|
||||
};
|
||||
use reqwest::StatusCode;
|
||||
use scel_core::App;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tower_http::{
|
||||
cors::CorsLayer,
|
||||
services::ServeDir,
|
||||
trace::{DefaultMakeSpan, TraceLayer},
|
||||
};
|
||||
|
||||
async fn graphql_playground() -> impl IntoResponse {
|
||||
Html(playground_source(
|
||||
GraphQLPlaygroundConfig::new("/graphql").subscription_endpoint("/ws"),
|
||||
))
|
||||
}
|
||||
async fn graphql_handler(
|
||||
schema: Extension<ScelSchema>,
|
||||
req: Json<Request>,
|
||||
_: User,
|
||||
) -> Json<Response> {
|
||||
schema.execute(req.0).await.into()
|
||||
}
|
||||
|
||||
pub struct Server {
|
||||
app: Router,
|
||||
addr: SocketAddr,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn new(app: Arc<App>) -> Server {
|
||||
let schema = Schema::build(QueryRoot, MutationRoot, SubscriptionRoot)
|
||||
.extension(Tracing)
|
||||
.extension(Logger)
|
||||
.data(app)
|
||||
.finish();
|
||||
|
||||
let cors = vec![
|
||||
"http://localhost:3000"
|
||||
.parse()
|
||||
.expect("Could not parse url"),
|
||||
"https://scel.front.kjuulh.io"
|
||||
.parse()
|
||||
.expect("Could not parse url"),
|
||||
];
|
||||
|
||||
let api_router = Router::new()
|
||||
.route(
|
||||
"/graphql",
|
||||
routing::get(graphql_playground).post(graphql_handler),
|
||||
)
|
||||
.route("/ws", GraphQLSubscription::new(schema.clone()))
|
||||
.route("/auth/gitea", routing::get(gitea))
|
||||
.route("/auth/authorized", routing::get(authorized))
|
||||
// .merge(axum_extra::routing::SpaRouter::new(
|
||||
// "/assets",
|
||||
// "src/web/dist/assets",
|
||||
// ))
|
||||
.fallback(get_service(ServeDir::new("./src/web/dist/")).handle_error(handle_error))
|
||||
.layer(Extension(schema))
|
||||
.layer(Extension(MemoryStore::new()))
|
||||
.layer(Extension(auth::oauth_client()))
|
||||
.layer(
|
||||
CorsLayer::new()
|
||||
.allow_origin(cors)
|
||||
.allow_headers([axum::http::header::CONTENT_TYPE])
|
||||
.allow_methods([Method::GET, Method::POST, Method::OPTIONS]),
|
||||
)
|
||||
.layer(TraceLayer::new_for_http().make_span_with(DefaultMakeSpan::default()));
|
||||
|
||||
let app = Router::new().nest("/api", api_router);
|
||||
|
||||
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
|
||||
|
||||
Server { app, addr }
|
||||
}
|
||||
|
||||
pub async fn start(self) -> anyhow::Result<()> {
|
||||
tracing::info!("listening on {}", self.addr);
|
||||
|
||||
match axum::Server::bind(&self.addr)
|
||||
.serve(self.app.into_make_service())
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct User {
|
||||
#[serde(alias = "sub")]
|
||||
id: String,
|
||||
#[serde(alias = "picture")]
|
||||
avatar: Option<String>,
|
||||
#[serde(alias = "email")]
|
||||
email: String,
|
||||
#[serde(alias = "preferred_username")]
|
||||
username: String,
|
||||
}
|
||||
|
||||
struct AuthRedirect;
|
||||
|
||||
impl IntoResponse for AuthRedirect {
|
||||
fn into_response(self) -> axum::response::Response {
|
||||
Redirect::temporary("/auth/gitea").into_response()
|
||||
}
|
||||
}
|
||||
|
||||
const COOKIE_NAME: &str = "auth";
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for User
|
||||
where
|
||||
B: Send,
|
||||
{
|
||||
type Rejection = AuthRedirect;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
let Extension(store) = Extension::<MemoryStore>::from_request(req)
|
||||
.await
|
||||
.expect("MemoryStore extension is missing");
|
||||
|
||||
let cookies = TypedHeader::<headers::Cookie>::from_request(req)
|
||||
.await
|
||||
.map_err(|e| match *e.name() {
|
||||
header::COOKIE => match e.reason() {
|
||||
TypedHeaderRejectionReason::Missing => AuthRedirect,
|
||||
_ => panic!("unexpected error getting Cookie header(s): {}", e),
|
||||
},
|
||||
_ => panic!("unexpected error getting cookies: {}", e),
|
||||
})?;
|
||||
|
||||
let session_cookie = cookies.get(COOKIE_NAME).ok_or(AuthRedirect)?;
|
||||
|
||||
let session = store
|
||||
.load_session(session_cookie.to_string())
|
||||
.await
|
||||
.expect("could not load session")
|
||||
.ok_or(AuthRedirect)?;
|
||||
|
||||
let user = session.get::<User>("user").ok_or(AuthRedirect)?;
|
||||
|
||||
Ok(user)
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_error(_err: io::Error) -> impl IntoResponse {
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong...")
|
||||
}
|
17
crates/scel_core/Cargo.toml
Normal file
17
crates/scel_core/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "scel_core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.22", features = ["full"] }
|
||||
anyhow = { version = "*" }
|
||||
async-trait = { version = "0.1.58" }
|
||||
futures = "0.3.30"
|
||||
tracing = "0.1"
|
||||
lazy_static = "1.4.0"
|
||||
regex = { version = "1.7.0" }
|
||||
thiserror = "2.0.0"
|
||||
uuid = {version = "1.2.2", features = ["v4", "fast-rng"]}
|
19
crates/scel_core/src/lib.rs
Normal file
19
crates/scel_core/src/lib.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use services::InMemoryDownloadService;
|
||||
|
||||
pub mod services;
|
||||
mod youtube;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct App {
|
||||
pub download_service: Arc<InMemoryDownloadService>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
download_service: Arc::new(InMemoryDownloadService::new()),
|
||||
}
|
||||
}
|
||||
}
|
3
crates/scel_core/src/repo/users_repo.rs
Normal file
3
crates/scel_core/src/repo/users_repo.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub trait UsersRepo {
|
||||
// add code here
|
||||
}
|
128
crates/scel_core/src/services/mod.rs
Normal file
128
crates/scel_core/src/services/mod.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
use std::{collections::HashMap, path::PathBuf, sync::Arc};
|
||||
use tokio::sync::{watch, Mutex};
|
||||
use tracing::error;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::youtube::{Arg, YoutubeDL};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Download {
|
||||
pub id: Option<String>,
|
||||
pub link: String,
|
||||
pub progress: Option<u32>,
|
||||
pub file_name: Option<String>,
|
||||
}
|
||||
|
||||
pub struct InMemoryDownloadService {
|
||||
downloads: Mutex<
|
||||
HashMap<
|
||||
String,
|
||||
(
|
||||
Arc<Mutex<Download>>,
|
||||
Arc<Mutex<tokio::sync::watch::Sender<Download>>>,
|
||||
tokio::sync::watch::Receiver<Download>,
|
||||
),
|
||||
>,
|
||||
>,
|
||||
}
|
||||
|
||||
impl InMemoryDownloadService {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
downloads: Mutex::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn add_download(self: Arc<Self>, download: Download) -> anyhow::Result<Download> {
|
||||
let mut downloads = self.downloads.lock().await;
|
||||
|
||||
let (tx, rx) = watch::channel(download.clone());
|
||||
let shared_tx = Arc::new(Mutex::new(tx));
|
||||
|
||||
let mut d = download.to_owned();
|
||||
|
||||
let id = Uuid::new_v4().to_string();
|
||||
d.id = Some(id.clone());
|
||||
|
||||
downloads.insert(id.clone(), (Arc::new(Mutex::new(d.clone())), shared_tx, rx));
|
||||
|
||||
let args = vec![
|
||||
Arg::new("--progress"),
|
||||
Arg::new("--newline"),
|
||||
Arg::new_with_args("--output", "%(title).90s.%(ext)s"),
|
||||
];
|
||||
let ytd = YoutubeDL::new(
|
||||
&PathBuf::from("./data/downloads"),
|
||||
args,
|
||||
download.link.as_str(),
|
||||
)?;
|
||||
|
||||
tokio::spawn({
|
||||
let download_service = self.clone();
|
||||
|
||||
async move {
|
||||
if let Err(e) = ytd
|
||||
.download(
|
||||
|percentage| {
|
||||
let ds = download_service.clone();
|
||||
let id = id.clone();
|
||||
|
||||
async move {
|
||||
let mut download = ds.get_download(id).await.unwrap().unwrap();
|
||||
download.progress = Some(percentage);
|
||||
let _ = ds.update_download(download).await;
|
||||
}
|
||||
},
|
||||
|file_name| {
|
||||
let ds = download_service.clone();
|
||||
let id = id.clone();
|
||||
|
||||
async move {
|
||||
let mut download = ds.get_download(id).await.unwrap().unwrap();
|
||||
download.file_name = Some(file_name);
|
||||
let _ = ds.update_download(download).await;
|
||||
}
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!("Download failed: {}", e);
|
||||
} else {
|
||||
let download = download_service.get_download(id).await.unwrap().unwrap();
|
||||
let _ = download_service.update_download(download).await;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(d)
|
||||
}
|
||||
|
||||
pub async fn update_download(self: Arc<Self>, download: Download) -> anyhow::Result<()> {
|
||||
let mut downloads = self.downloads.lock().await;
|
||||
if let Some(d) = downloads.get_mut(&download.clone().id.unwrap()) {
|
||||
let mut d_mut = d.0.lock().await;
|
||||
*d_mut = download.clone();
|
||||
let _ = d.1.lock().await.send(download);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_download(&self, id: String) -> anyhow::Result<Option<Download>> {
|
||||
let downloads = self.downloads.lock().await;
|
||||
|
||||
if let Some(d) = downloads.get(&id) {
|
||||
let download = d.0.lock().await;
|
||||
|
||||
Ok(Some(download.clone()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn subscribe_download(&self, id: String) -> tokio::sync::watch::Receiver<Download> {
|
||||
let downloads = self.downloads.lock().await;
|
||||
let download = downloads.get(&id).unwrap();
|
||||
download.2.clone()
|
||||
}
|
||||
}
|
256
crates/scel_core/src/youtube/mod.rs
Normal file
256
crates/scel_core/src/youtube/mod.rs
Normal file
@@ -0,0 +1,256 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::fs::{canonicalize, create_dir_all};
|
||||
use std::future::Future;
|
||||
use std::num::ParseIntError;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Output, Stdio};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use thiserror::Error;
|
||||
use tokio::io::{AsyncBufReadExt, BufReader};
|
||||
use tokio::process::Command;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum YoutubeDLError {
|
||||
#[error("failed to execute youtube-dl")]
|
||||
IOError(#[from] std::io::Error),
|
||||
#[error("failed to convert path")]
|
||||
UTF8Error(#[from] std::string::FromUtf8Error),
|
||||
#[error("youtube-dl exited with: {0}")]
|
||||
Failure(String),
|
||||
}
|
||||
|
||||
type Result<T> = std::result::Result<T, YoutubeDLError>;
|
||||
|
||||
const YOUTUBE_DL_COMMAND: &str = "yt-dlp";
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Arg {
|
||||
arg: String,
|
||||
input: Option<String>,
|
||||
}
|
||||
|
||||
impl Arg {
|
||||
pub fn new(argument: &str) -> Self {
|
||||
Self {
|
||||
arg: argument.to_string(),
|
||||
input: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_args(argument: &str, input: &str) -> Self {
|
||||
Self {
|
||||
arg: argument.to_string(),
|
||||
input: Option::from(input.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Arg {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match &self.input {
|
||||
Some(input) => write!(fmt, "{} {}", self.arg, input),
|
||||
None => write!(fmt, "{}", self.arg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct YoutubeDL {
|
||||
path: PathBuf,
|
||||
links: Vec<String>,
|
||||
args: Vec<Arg>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct YoutubeDLResult {
|
||||
path: PathBuf,
|
||||
output: String,
|
||||
}
|
||||
|
||||
impl YoutubeDLResult {
|
||||
fn new(path: &PathBuf) -> Self {
|
||||
Self {
|
||||
path: path.clone(),
|
||||
output: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output_dir(&self) -> &PathBuf {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
|
||||
impl YoutubeDL {
|
||||
pub fn new_multiple_links(
|
||||
dl_path: &PathBuf,
|
||||
args: Vec<Arg>,
|
||||
links: Vec<String>,
|
||||
) -> Result<YoutubeDL> {
|
||||
let path = Path::new(dl_path);
|
||||
|
||||
if !path.exists() {
|
||||
create_dir_all(&path)?;
|
||||
}
|
||||
|
||||
if !path.is_dir() {
|
||||
return Err(YoutubeDLError::IOError(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"path is not a directory",
|
||||
)));
|
||||
}
|
||||
|
||||
let path = canonicalize(dl_path)?;
|
||||
Ok(YoutubeDL { path, links, args })
|
||||
}
|
||||
|
||||
pub fn new(dl_path: &PathBuf, args: Vec<Arg>, link: &str) -> Result<YoutubeDL> {
|
||||
YoutubeDL::new_multiple_links(dl_path, args, vec![link.to_string()])
|
||||
}
|
||||
|
||||
pub async fn download<F, FutAvailable, FAvailable, Fut>(
|
||||
&self,
|
||||
progress_update_fn: F,
|
||||
file_name_available: FAvailable,
|
||||
) -> Result<YoutubeDLResult>
|
||||
where
|
||||
F: Fn(u32) -> Fut,
|
||||
FAvailable: Fn(String) -> FutAvailable,
|
||||
Fut: Future<Output = ()>,
|
||||
FutAvailable: Future<Output = ()>,
|
||||
{
|
||||
let output = self
|
||||
.spawn_youtube_dl(progress_update_fn, file_name_available)
|
||||
.await?;
|
||||
let mut result = YoutubeDLResult::new(&self.path);
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(YoutubeDLError::Failure(String::from_utf8(output.stderr)?));
|
||||
}
|
||||
result.output = String::from_utf8(output.stdout)?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
async fn spawn_youtube_dl<F, FutAvailable, FAvailable, Fut>(
|
||||
&self,
|
||||
progress_update_fn: F,
|
||||
file_name_available: FAvailable,
|
||||
) -> Result<Output>
|
||||
where
|
||||
F: Fn(u32) -> Fut,
|
||||
FAvailable: Fn(String) -> FutAvailable,
|
||||
Fut: Future<Output = ()>,
|
||||
FutAvailable: Future<Output = ()>,
|
||||
{
|
||||
let mut cmd = Command::new(YOUTUBE_DL_COMMAND);
|
||||
cmd.current_dir(&self.path)
|
||||
.env("LC_ALL", "en_US.UTF-8")
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped());
|
||||
|
||||
for arg in self.args.iter() {
|
||||
match &arg.input {
|
||||
Some(input) => cmd.arg(&arg.arg).arg(input),
|
||||
None => cmd.arg(&arg.arg),
|
||||
};
|
||||
}
|
||||
|
||||
for link in self.links.iter() {
|
||||
cmd.arg(&link);
|
||||
}
|
||||
|
||||
let mut pr = cmd.spawn()?;
|
||||
|
||||
{
|
||||
let stdout = pr.stdout.as_mut().unwrap();
|
||||
let stdout_reader = BufReader::new(stdout);
|
||||
let mut stdout_lines = stdout_reader.lines();
|
||||
|
||||
let mut have_gotten_file_name = false;
|
||||
while let Ok(Some(line)) = stdout_lines.next_line().await {
|
||||
println!("{}", line.clone());
|
||||
|
||||
if !have_gotten_file_name {
|
||||
if let Some(file_name) = parse_file_name(line.clone()) {
|
||||
file_name_available(file_name).await;
|
||||
have_gotten_file_name = true
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(Ok(percentage)) = parse_line(line) {
|
||||
progress_update_fn(percentage).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(pr.wait_with_output().await?)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_line(line: String) -> Option<core::result::Result<u32, ParseIntError>> {
|
||||
lazy_static! {
|
||||
static ref RE: Regex = Regex::new(r"\[download\]\s+(\d+)").unwrap();
|
||||
}
|
||||
|
||||
let capture: regex::Captures = RE.captures(line.as_str())?;
|
||||
if capture.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
let str = &capture[1];
|
||||
Some(str.to_string().parse::<u32>())
|
||||
}
|
||||
|
||||
fn parse_file_name(line: String) -> Option<String> {
|
||||
lazy_static! {
|
||||
static ref RE: Regex = Regex::new(r"^\[download\] Destination: (.+)$").unwrap();
|
||||
}
|
||||
|
||||
let capture: regex::Captures = RE.captures(line.as_str())?;
|
||||
if capture.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
let str = &capture[1];
|
||||
Some(str.to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::youtube::{parse_file_name, parse_line};
|
||||
|
||||
#[test]
|
||||
fn test_parse_line() {
|
||||
let percentage = parse_line(
|
||||
"[download] 95.4% of ~215.85MiB at 9.61MiB/s ETA 00:01 (frag 144/151)".into(),
|
||||
);
|
||||
|
||||
assert_eq!(percentage, Some(Ok(95)))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_line_get_nothing() {
|
||||
let nothing = parse_line("[download] Got server HTTP error: The read operation timed out. Retrying (attempt 1 of 10) ...".into());
|
||||
|
||||
assert_eq!(nothing, None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_file_name() {
|
||||
let file_name = parse_file_name(
|
||||
"[download] Destination: 10 Design Patterns Explained in 10 Minutes.mp4".into(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
file_name,
|
||||
Some("10 Design Patterns Explained in 10 Minutes.mp4".into())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_file_name_get_nothing() {
|
||||
let nothing = parse_file_name("[download] No fit: something".into());
|
||||
|
||||
assert_eq!(nothing, None)
|
||||
}
|
||||
}
|
21
cuddle.yaml
Normal file
21
cuddle.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
# yaml-language-server: $schema=https://git.front.kjuulh.io/kjuulh/cuddle/raw/branch/main/schemas/base.json
|
||||
|
||||
base: "git@git.front.kjuulh.io:kjuulh/cuddle-rust-service-plan.git"
|
||||
|
||||
vars:
|
||||
service: "scel"
|
||||
registry: kasperhermansen
|
||||
|
||||
clusters:
|
||||
clank-prod:
|
||||
replicas: "3"
|
||||
namespace: prod
|
||||
|
||||
|
||||
deployment:
|
||||
registry: git@git.front.kjuulh.io:kjuulh/clank-clusters
|
||||
env:
|
||||
prod:
|
||||
clusters:
|
||||
- clank-prod
|
||||
|
BIN
data/downloads/The Blimp Extinction.mp4.part
Normal file
BIN
data/downloads/The Blimp Extinction.mp4.part
Normal file
Binary file not shown.
3
renovate.json
Normal file
3
renovate.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
use tracing::{info, Level};
|
||||
use tracing_subscriber::FmtSubscriber;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let subscriber = FmtSubscriber::builder()
|
||||
.with_max_level(Level::INFO)
|
||||
.finish();
|
||||
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
|
||||
info!("Starting scel");
|
||||
|
||||
scel_api::Server::new().start().await
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
[package]
|
||||
name = "scel_api"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
axum = { version = "0.5.6" }
|
||||
futures = "0.3.21"
|
||||
tower-http = {version = "0.3.3", features = ["cors"]}
|
||||
async-graphql = { version = "4.0.0" }
|
||||
async-graphql-axum = { version = "4.0.0" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0.68"
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3" }
|
||||
anyhow = { version = "1.0.58" }
|
@@ -1,72 +0,0 @@
|
||||
mod mutation;
|
||||
mod query;
|
||||
mod schema;
|
||||
mod subscription;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use async_graphql::{
|
||||
http::{playground_source, GraphQLPlaygroundConfig},
|
||||
Request, Response, Schema,
|
||||
};
|
||||
use async_graphql_axum::GraphQLSubscription;
|
||||
use axum::{
|
||||
http::Method,
|
||||
response::{Html, IntoResponse},
|
||||
routing, Extension, Json, Router,
|
||||
};
|
||||
use mutation::MutationRoot;
|
||||
use query::QueryRoot;
|
||||
use schema::ScelSchema;
|
||||
use subscription::SubscriptionRoot;
|
||||
use tower_http::cors::CorsLayer;
|
||||
|
||||
async fn graphql_playground() -> impl IntoResponse {
|
||||
Html(playground_source(
|
||||
GraphQLPlaygroundConfig::new("/").subscription_endpoint("/ws"),
|
||||
))
|
||||
}
|
||||
async fn graphql_handler(schema: Extension<ScelSchema>, req: Json<Request>) -> Json<Response> {
|
||||
schema.execute(req.0).await.into()
|
||||
}
|
||||
|
||||
pub struct Server {
|
||||
app: Router,
|
||||
addr: SocketAddr,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn new() -> Server {
|
||||
let schema = Schema::build(QueryRoot, MutationRoot, SubscriptionRoot).finish();
|
||||
|
||||
let cors = vec!["http://localhost:3000"
|
||||
.parse()
|
||||
.expect("Could not parse url")];
|
||||
|
||||
let app = Router::new()
|
||||
.route("/", routing::get(graphql_playground).post(graphql_handler))
|
||||
.route("/ws", GraphQLSubscription::new(schema.clone()))
|
||||
.layer(Extension(schema))
|
||||
.layer(
|
||||
CorsLayer::new()
|
||||
.allow_origin(cors)
|
||||
.allow_headers([axum::http::header::CONTENT_TYPE])
|
||||
.allow_methods([Method::GET, Method::POST, Method::OPTIONS]),
|
||||
);
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
|
||||
return Server { app, addr };
|
||||
}
|
||||
|
||||
pub async fn start(self) -> anyhow::Result<()> {
|
||||
tracing::info!("listening on {}", self.addr);
|
||||
|
||||
match axum::Server::bind(&self.addr)
|
||||
.serve(self.app.into_make_service())
|
||||
.await
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
use async_graphql::{Context, Object, Result, SimpleObject, ID};
|
||||
|
||||
pub struct MutationRoot;
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
struct RequestDownloadResponse {
|
||||
id: ID,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl MutationRoot {
|
||||
async fn request_download(&self, ctx: &Context<'_>) -> Result<RequestDownloadResponse> {
|
||||
Err("not implemented 123".into())
|
||||
}
|
||||
}
|
@@ -1,10 +0,0 @@
|
||||
use async_graphql::Object;
|
||||
|
||||
pub struct QueryRoot;
|
||||
|
||||
#[Object]
|
||||
impl QueryRoot {
|
||||
async fn hello_world(&self) -> &str {
|
||||
"Hello, world!"
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
use async_graphql::{
|
||||
async_stream::stream, futures_util::Stream, Context, Object, Subscription, ID,
|
||||
};
|
||||
|
||||
pub struct SubscriptionRoot;
|
||||
|
||||
struct DownloadChanged {
|
||||
id: ID,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl DownloadChanged {
|
||||
async fn id(&self) -> &ID {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
#[Subscription]
|
||||
impl SubscriptionRoot {
|
||||
async fn get_download(&self, ctx: &Context<'_>) -> impl Stream<Item = DownloadChanged> {
|
||||
stream! {
|
||||
yield DownloadChanged {id: "Some-id".into()}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "scel_core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
@@ -1,12 +0,0 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = 2 + 2;
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn something() -> String {
|
||||
"".into()
|
||||
}
|
1
web/.dockerignore
Normal file
1
web/.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
node_modules/
|
24
web/.gitignore
vendored
Normal file
24
web/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
13
web/index.html
Normal file
13
web/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!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>Vite + React + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
22
web/package.json
Normal file
22
web/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "web",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "19.0.10",
|
||||
"@types/react-dom": "19.0.4",
|
||||
"@vitejs/plugin-react": "4.6.0",
|
||||
"typescript": "5.8.3",
|
||||
"vite": "7.0.4"
|
||||
}
|
||||
}
|
1
web/public/vite.svg
Normal file
1
web/public/vite.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
12
web/src/App.tsx
Normal file
12
web/src/App.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import Body from "./components/body/Body"
|
||||
import Navbar from "./components/navbar/Navbar"
|
||||
import RequestDownload from "./components/request-download/RequestDownload"
|
||||
|
||||
const App = () => <div>
|
||||
<Navbar />
|
||||
<Body>
|
||||
<RequestDownload />
|
||||
</Body>
|
||||
</div>
|
||||
|
||||
export default App
|
1
web/src/assets/react.svg
Normal file
1
web/src/assets/react.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
After Width: | Height: | Size: 4.0 KiB |
8
web/src/components/body/Body.tsx
Normal file
8
web/src/components/body/Body.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import { FC, ReactNode } from "react"
|
||||
|
||||
interface BodyProps {
|
||||
children?: ReactNode
|
||||
}
|
||||
const Body: FC<BodyProps> = ({ children }) => <div>{children}</div>
|
||||
|
||||
export default Body
|
10
web/src/components/navbar/Navbar.tsx
Normal file
10
web/src/components/navbar/Navbar.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import { getServerUrl } from "../../lib/env"
|
||||
|
||||
const Navbar = () => {
|
||||
return <nav>
|
||||
<div>Scel</div>
|
||||
<a href={`${getServerUrl()}/auth/gitea`}>Login</a>
|
||||
</nav>
|
||||
}
|
||||
|
||||
export default Navbar
|
7
web/src/components/request-download/RequestDownload.tsx
Normal file
7
web/src/components/request-download/RequestDownload.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
const RequestDownload = () => {
|
||||
return <div>
|
||||
<input type="text" placeholder="Request download"></input>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default RequestDownload
|
3
web/src/lib/env.ts
Normal file
3
web/src/lib/env.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const getServerUrl = (): string => {
|
||||
return import.meta.env.VITE_SERVER_BASE_URL
|
||||
}
|
9
web/src/main.tsx
Normal file
9
web/src/main.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
)
|
1
web/src/vite-env.d.ts
vendored
Normal file
1
web/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
21
web/tsconfig.json
Normal file
21
web/tsconfig.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"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" }]
|
||||
}
|
9
web/tsconfig.node.json
Normal file
9
web/tsconfig.node.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
7
web/vite.config.ts
Normal file
7
web/vite.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()]
|
||||
})
|
755
web/yarn.lock
Normal file
755
web/yarn.lock
Normal file
@@ -0,0 +1,755 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@ampproject/remapping@^2.2.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4"
|
||||
integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==
|
||||
dependencies:
|
||||
"@jridgewell/gen-mapping" "^0.3.5"
|
||||
"@jridgewell/trace-mapping" "^0.3.24"
|
||||
|
||||
"@babel/code-frame@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be"
|
||||
integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.27.1"
|
||||
js-tokens "^4.0.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
"@babel/compat-data@^7.27.2":
|
||||
version "7.28.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.0.tgz#9fc6fd58c2a6a15243cd13983224968392070790"
|
||||
integrity sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==
|
||||
|
||||
"@babel/core@^7.27.4":
|
||||
version "7.28.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.0.tgz#55dad808d5bf3445a108eefc88ea3fdf034749a4"
|
||||
integrity sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==
|
||||
dependencies:
|
||||
"@ampproject/remapping" "^2.2.0"
|
||||
"@babel/code-frame" "^7.27.1"
|
||||
"@babel/generator" "^7.28.0"
|
||||
"@babel/helper-compilation-targets" "^7.27.2"
|
||||
"@babel/helper-module-transforms" "^7.27.3"
|
||||
"@babel/helpers" "^7.27.6"
|
||||
"@babel/parser" "^7.28.0"
|
||||
"@babel/template" "^7.27.2"
|
||||
"@babel/traverse" "^7.28.0"
|
||||
"@babel/types" "^7.28.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.28.0":
|
||||
version "7.28.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.0.tgz#9cc2f7bd6eb054d77dc66c2664148a0c5118acd2"
|
||||
integrity sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.28.0"
|
||||
"@babel/types" "^7.28.0"
|
||||
"@jridgewell/gen-mapping" "^0.3.12"
|
||||
"@jridgewell/trace-mapping" "^0.3.28"
|
||||
jsesc "^3.0.2"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.27.2":
|
||||
version "7.27.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d"
|
||||
integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.27.2"
|
||||
"@babel/helper-validator-option" "^7.27.1"
|
||||
browserslist "^4.24.0"
|
||||
lru-cache "^5.1.1"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-globals@^7.28.0":
|
||||
version "7.28.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674"
|
||||
integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==
|
||||
|
||||
"@babel/helper-module-imports@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204"
|
||||
integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.27.1"
|
||||
"@babel/types" "^7.27.1"
|
||||
|
||||
"@babel/helper-module-transforms@^7.27.3":
|
||||
version "7.27.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz#db0bbcfba5802f9ef7870705a7ef8788508ede02"
|
||||
integrity sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.27.1"
|
||||
"@babel/helper-validator-identifier" "^7.27.1"
|
||||
"@babel/traverse" "^7.27.3"
|
||||
|
||||
"@babel/helper-plugin-utils@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c"
|
||||
integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==
|
||||
|
||||
"@babel/helper-string-parser@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
|
||||
integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8"
|
||||
integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==
|
||||
|
||||
"@babel/helper-validator-option@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f"
|
||||
integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==
|
||||
|
||||
"@babel/helpers@^7.27.6":
|
||||
version "7.27.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.6.tgz#6456fed15b2cb669d2d1fabe84b66b34991d812c"
|
||||
integrity sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==
|
||||
dependencies:
|
||||
"@babel/template" "^7.27.2"
|
||||
"@babel/types" "^7.27.6"
|
||||
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.27.2", "@babel/parser@^7.28.0":
|
||||
version "7.28.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e"
|
||||
integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==
|
||||
dependencies:
|
||||
"@babel/types" "^7.28.0"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-self@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz#af678d8506acf52c577cac73ff7fe6615c85fc92"
|
||||
integrity sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.27.1"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-source@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz#dcfe2c24094bb757bf73960374e7c55e434f19f0"
|
||||
integrity sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.27.1"
|
||||
|
||||
"@babel/template@^7.27.2":
|
||||
version "7.27.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d"
|
||||
integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.27.1"
|
||||
"@babel/parser" "^7.27.2"
|
||||
"@babel/types" "^7.27.1"
|
||||
|
||||
"@babel/traverse@^7.27.1", "@babel/traverse@^7.27.3", "@babel/traverse@^7.28.0":
|
||||
version "7.28.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.0.tgz#518aa113359b062042379e333db18380b537e34b"
|
||||
integrity sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.27.1"
|
||||
"@babel/generator" "^7.28.0"
|
||||
"@babel/helper-globals" "^7.28.0"
|
||||
"@babel/parser" "^7.28.0"
|
||||
"@babel/template" "^7.27.2"
|
||||
"@babel/types" "^7.28.0"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.1", "@babel/types@^7.27.6", "@babel/types@^7.28.0":
|
||||
version "7.28.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.0.tgz#2fd0159a6dc7353933920c43136335a9b264d950"
|
||||
integrity sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.27.1"
|
||||
"@babel/helper-validator-identifier" "^7.27.1"
|
||||
|
||||
"@esbuild/aix-ppc64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz#164b19122e2ed54f85469df9dea98ddb01d5e79e"
|
||||
integrity sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==
|
||||
|
||||
"@esbuild/android-arm64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.6.tgz#8f539e7def848f764f6432598e51cc3820fde3a5"
|
||||
integrity sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==
|
||||
|
||||
"@esbuild/android-arm@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.6.tgz#4ceb0f40113e9861169be83e2a670c260dd234ff"
|
||||
integrity sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==
|
||||
|
||||
"@esbuild/android-x64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.6.tgz#ad4f280057622c25fe985c08999443a195dc63a8"
|
||||
integrity sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==
|
||||
|
||||
"@esbuild/darwin-arm64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.6.tgz#d1f04027396b3d6afc96bacd0d13167dfd9f01f7"
|
||||
integrity sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==
|
||||
|
||||
"@esbuild/darwin-x64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.6.tgz#2b4a6cedb799f635758d7832d75b23772c8ef68f"
|
||||
integrity sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==
|
||||
|
||||
"@esbuild/freebsd-arm64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.6.tgz#a26266cc97dd78dc3c3f3d6788b1b83697b1055d"
|
||||
integrity sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==
|
||||
|
||||
"@esbuild/freebsd-x64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.6.tgz#9feb8e826735c568ebfd94859b22a3fbb6a9bdd2"
|
||||
integrity sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==
|
||||
|
||||
"@esbuild/linux-arm64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.6.tgz#c07cbed8e249f4c28e7f32781d36fc4695293d28"
|
||||
integrity sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==
|
||||
|
||||
"@esbuild/linux-arm@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.6.tgz#d6e2cd8ef3196468065d41f13fa2a61aaa72644a"
|
||||
integrity sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==
|
||||
|
||||
"@esbuild/linux-ia32@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.6.tgz#3e682bd47c4eddcc4b8f1393dfc8222482f17997"
|
||||
integrity sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==
|
||||
|
||||
"@esbuild/linux-loong64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.6.tgz#473f5ea2e52399c08ad4cd6b12e6dbcddd630f05"
|
||||
integrity sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==
|
||||
|
||||
"@esbuild/linux-mips64el@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.6.tgz#9960631c9fd61605b0939c19043acf4ef2b51718"
|
||||
integrity sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==
|
||||
|
||||
"@esbuild/linux-ppc64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.6.tgz#477cbf8bb04aa034b94f362c32c86b5c31db8d3e"
|
||||
integrity sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==
|
||||
|
||||
"@esbuild/linux-riscv64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.6.tgz#bcdb46c8fb8e93aa779e9a0a62cd4ac00dcac626"
|
||||
integrity sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==
|
||||
|
||||
"@esbuild/linux-s390x@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.6.tgz#f412cf5fdf0aea849ff51c73fd817c6c0234d46d"
|
||||
integrity sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==
|
||||
|
||||
"@esbuild/linux-x64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.6.tgz#d8233c09b5ebc0c855712dc5eeb835a3a3341108"
|
||||
integrity sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==
|
||||
|
||||
"@esbuild/netbsd-arm64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.6.tgz#f51ae8dd1474172e73cf9cbaf8a38d1c72dd8f1a"
|
||||
integrity sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==
|
||||
|
||||
"@esbuild/netbsd-x64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.6.tgz#a267538602c0e50a858cf41dcfe5d8036f8da8e7"
|
||||
integrity sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==
|
||||
|
||||
"@esbuild/openbsd-arm64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.6.tgz#a51be60c425b85c216479b8c344ad0511635f2d2"
|
||||
integrity sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==
|
||||
|
||||
"@esbuild/openbsd-x64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.6.tgz#7e4a743c73f75562e29223ba69d0be6c9c9008da"
|
||||
integrity sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==
|
||||
|
||||
"@esbuild/openharmony-arm64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.6.tgz#2087a5028f387879154ebf44bdedfafa17682e5b"
|
||||
integrity sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==
|
||||
|
||||
"@esbuild/sunos-x64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.6.tgz#56531f861723ea0dc6283a2bb8837304223cb736"
|
||||
integrity sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==
|
||||
|
||||
"@esbuild/win32-arm64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.6.tgz#f4989f033deac6fae323acff58764fa8bc01436e"
|
||||
integrity sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==
|
||||
|
||||
"@esbuild/win32-ia32@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.6.tgz#b260e9df71e3939eb33925076d39f63cec7d1525"
|
||||
integrity sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==
|
||||
|
||||
"@esbuild/win32-x64@0.25.6":
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz#4276edd5c105bc28b11c6a1f76fb9d29d1bd25c1"
|
||||
integrity sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==
|
||||
|
||||
"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5":
|
||||
version "0.3.12"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz#2234ce26c62889f03db3d7fea43c1932ab3e927b"
|
||||
integrity sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==
|
||||
dependencies:
|
||||
"@jridgewell/sourcemap-codec" "^1.5.0"
|
||||
"@jridgewell/trace-mapping" "^0.3.24"
|
||||
|
||||
"@jridgewell/resolve-uri@^3.1.0":
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
|
||||
integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0":
|
||||
version "1.5.4"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz#7358043433b2e5da569aa02cbc4c121da3af27d7"
|
||||
integrity sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28":
|
||||
version "0.3.29"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz#a58d31eaadaf92c6695680b2e1d464a9b8fbf7fc"
|
||||
integrity sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri" "^3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||
|
||||
"@rolldown/pluginutils@1.0.0-beta.19":
|
||||
version "1.0.0-beta.19"
|
||||
resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz#fc3b95145a8e7a3bf92754269d8e4f40eea8a244"
|
||||
integrity sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.2.tgz#6819b7f1e41a49af566f629a1556eaeea774d043"
|
||||
integrity sha512-g0dF8P1e2QYPOj1gu7s/3LVP6kze9A7m6x0BZ9iTdXK8N5c2V7cpBKHV3/9A4Zd8xxavdhK0t4PnqjkqVmUc9Q==
|
||||
|
||||
"@rollup/rollup-android-arm64@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.2.tgz#7bd5591af68c64a75be1779e2b20f187878daba9"
|
||||
integrity sha512-Yt5MKrOosSbSaAK5Y4J+vSiID57sOvpBNBR6K7xAaQvk3MkcNVV0f9fE20T+41WYN8hDn6SGFlFrKudtx4EoxA==
|
||||
|
||||
"@rollup/rollup-darwin-arm64@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.2.tgz#e216c333e448c67973386e46dbfe8e381aafb055"
|
||||
integrity sha512-EsnFot9ZieM35YNA26nhbLTJBHD0jTwWpPwmRVDzjylQT6gkar+zenfb8mHxWpRrbn+WytRRjE0WKsfaxBkVUA==
|
||||
|
||||
"@rollup/rollup-darwin-x64@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.2.tgz#202f80eea3acfe3f67496fedffa006a5f1ce7f5a"
|
||||
integrity sha512-dv/t1t1RkCvJdWWxQ2lWOO+b7cMsVw5YFaS04oHpZRWehI1h0fV1gF4wgGCTyQHHjJDfbNpwOi6PXEafRBBezw==
|
||||
|
||||
"@rollup/rollup-freebsd-arm64@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.2.tgz#4880f9769f1a7eec436b9c146e1d714338c26567"
|
||||
integrity sha512-W4tt4BLorKND4qeHElxDoim0+BsprFTwb+vriVQnFFtT/P6v/xO5I99xvYnVzKWrK6j7Hb0yp3x7V5LUbaeOMg==
|
||||
|
||||
"@rollup/rollup-freebsd-x64@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.2.tgz#647d6e333349b1c0fb322c2827ba1a53a0f10301"
|
||||
integrity sha512-tdT1PHopokkuBVyHjvYehnIe20fxibxFCEhQP/96MDSOcyjM/shlTkZZLOufV3qO6/FQOSiJTBebhVc12JyPTA==
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.2.tgz#7ba5c97a7224f49618861d093c4a7b40fa50867b"
|
||||
integrity sha512-+xmiDGGaSfIIOXMzkhJ++Oa0Gwvl9oXUeIiwarsdRXSe27HUIvjbSIpPxvnNsRebsNdUo7uAiQVgBD1hVriwSQ==
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.2.tgz#f858dcf498299d6c625ec697a5191e0e41423905"
|
||||
integrity sha512-bDHvhzOfORk3wt8yxIra8N4k/N0MnKInCW5OGZaeDYa/hMrdPaJzo7CSkjKZqX4JFUWjUGm88lI6QJLCM7lDrA==
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.2.tgz#c0f1fc20c50666c61f574536a00cdd486b6aaae1"
|
||||
integrity sha512-NMsDEsDiYghTbeZWEGnNi4F0hSbGnsuOG+VnNvxkKg0IGDvFh7UVpM/14mnMwxRxUf9AdAVJgHPvKXf6FpMB7A==
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.2.tgz#0214efc3e404ddf108e946ad5f7e4ee2792a155a"
|
||||
integrity sha512-lb5bxXnxXglVq+7imxykIp5xMq+idehfl+wOgiiix0191av84OqbjUED+PRC5OA8eFJYj5xAGcpAZ0pF2MnW+A==
|
||||
|
||||
"@rollup/rollup-linux-loongarch64-gnu@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.2.tgz#8303c4ea2ae7bcbb96b2c77cfb53527d964bfceb"
|
||||
integrity sha512-Yl5Rdpf9pIc4GW1PmkUGHdMtbx0fBLE1//SxDmuf3X0dUC57+zMepow2LK0V21661cjXdTn8hO2tXDdAWAqE5g==
|
||||
|
||||
"@rollup/rollup-linux-powerpc64le-gnu@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.2.tgz#4197ffbc61809629094c0fccf825e43a40fbc0ca"
|
||||
integrity sha512-03vUDH+w55s680YYryyr78jsO1RWU9ocRMaeV2vMniJJW/6HhoTBwyyiiTPVHNWLnhsnwcQ0oH3S9JSBEKuyqw==
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.2.tgz#bcb99c9004c9b91e3704a6a70c892cb0599b1f42"
|
||||
integrity sha512-iYtAqBg5eEMG4dEfVlkqo05xMOk6y/JXIToRca2bAWuqjrJYJlx/I7+Z+4hSrsWU8GdJDFPL4ktV3dy4yBSrzg==
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.2.tgz#3e943bae9b8b4637c573c1922392beb8a5e81acb"
|
||||
integrity sha512-e6vEbgaaqz2yEHqtkPXa28fFuBGmUJ0N2dOJK8YUfijejInt9gfCSA7YDdJ4nYlv67JfP3+PSWFX4IVw/xRIPg==
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.2.tgz#dc43fb467bff9547f5b9937f38668da07fa8fa9f"
|
||||
integrity sha512-evFOtkmVdY3udE+0QKrV5wBx7bKI0iHz5yEVx5WqDJkxp9YQefy4Mpx3RajIVcM6o7jxTvVd/qpC1IXUhGc1Mw==
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.2.tgz#0699c560fa6ce6b846581a7e6c30c85c22a3f0da"
|
||||
integrity sha512-/bXb0bEsWMyEkIsUL2Yt5nFB5naLAwyOWMEviQfQY1x3l5WsLKgvZf66TM7UTfED6erckUVUJQ/jJ1FSpm3pRQ==
|
||||
|
||||
"@rollup/rollup-linux-x64-musl@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.2.tgz#9fb1becedcdc9e227d4748576eb8ba2fad8d2e29"
|
||||
integrity sha512-3D3OB1vSSBXmkGEZR27uiMRNiwN08/RVAcBKwhUYPaiZ8bcvdeEwWPvbnXvvXHY+A/7xluzcN+kaiOFNiOZwWg==
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.2.tgz#fcf3e62edd76c560252b819f69627685f65887d7"
|
||||
integrity sha512-VfU0fsMK+rwdK8mwODqYeM2hDrF2WiHaSmCBrS7gColkQft95/8tphyzv2EupVxn3iE0FI78wzffoULH1G+dkw==
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.2.tgz#45a5304491d6da4666f6159be4f739d4d43a283f"
|
||||
integrity sha512-+qMUrkbUurpE6DVRjiJCNGZBGo9xM4Y0FXU5cjgudWqIBWbcLkjE3XprJUsOFgC6xjBClwVa9k6O3A7K3vxb5Q==
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc@4.44.2":
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.2.tgz#660018c9696ad4f48abe8c5d56db53c81aadba25"
|
||||
integrity sha512-3+QZROYfJ25PDcxFF66UEk8jGWigHJeecZILvkPkyQN7oc5BvFo4YEXFkOs154j3FTMp9mn9Ky8RCOwastduEA==
|
||||
|
||||
"@types/babel__core@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017"
|
||||
integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.20.7"
|
||||
"@babel/types" "^7.20.7"
|
||||
"@types/babel__generator" "*"
|
||||
"@types/babel__template" "*"
|
||||
"@types/babel__traverse" "*"
|
||||
|
||||
"@types/babel__generator@*":
|
||||
version "7.27.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9"
|
||||
integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.0.0"
|
||||
|
||||
"@types/babel__template@*":
|
||||
version "7.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f"
|
||||
integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.1.0"
|
||||
"@babel/types" "^7.0.0"
|
||||
|
||||
"@types/babel__traverse@*":
|
||||
version "7.20.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.7.tgz#968cdc2366ec3da159f61166428ee40f370e56c2"
|
||||
integrity sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==
|
||||
dependencies:
|
||||
"@babel/types" "^7.20.7"
|
||||
|
||||
"@types/estree@1.0.8":
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e"
|
||||
integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==
|
||||
|
||||
"@types/react-dom@19.0.4":
|
||||
version "19.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.0.4.tgz#bedba97f9346bd4c0fe5d39e689713804ec9ac89"
|
||||
integrity sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==
|
||||
|
||||
"@types/react@19.0.10":
|
||||
version "19.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.10.tgz#d0c66dafd862474190fe95ce11a68de69ed2b0eb"
|
||||
integrity sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==
|
||||
dependencies:
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@vitejs/plugin-react@4.6.0":
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.6.0.tgz#2707b485f44806d42d41c63921883cff9c54dfaa"
|
||||
integrity sha512-5Kgff+m8e2PB+9j51eGHEpn5kUzRKH2Ry0qGoe8ItJg7pqnkPrYPkDQZGgGmTa0EGarHrkjLvOdU3b1fzI8otQ==
|
||||
dependencies:
|
||||
"@babel/core" "^7.27.4"
|
||||
"@babel/plugin-transform-react-jsx-self" "^7.27.1"
|
||||
"@babel/plugin-transform-react-jsx-source" "^7.27.1"
|
||||
"@rolldown/pluginutils" "1.0.0-beta.19"
|
||||
"@types/babel__core" "^7.20.5"
|
||||
react-refresh "^0.17.0"
|
||||
|
||||
browserslist@^4.24.0:
|
||||
version "4.25.1"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.1.tgz#ba9e8e6f298a1d86f829c9b975e07948967bb111"
|
||||
integrity sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==
|
||||
dependencies:
|
||||
caniuse-lite "^1.0.30001726"
|
||||
electron-to-chromium "^1.5.173"
|
||||
node-releases "^2.0.19"
|
||||
update-browserslist-db "^1.1.3"
|
||||
|
||||
caniuse-lite@^1.0.30001726:
|
||||
version "1.0.30001727"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz#22e9706422ad37aa50556af8c10e40e2d93a8b85"
|
||||
integrity sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==
|
||||
|
||||
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.0"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2"
|
||||
integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==
|
||||
|
||||
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"
|
||||
|
||||
debug@^4.3.1:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
|
||||
integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==
|
||||
dependencies:
|
||||
ms "^2.1.3"
|
||||
|
||||
electron-to-chromium@^1.5.173:
|
||||
version "1.5.182"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.182.tgz#4ab73104f893938acb3ab9c28d7bec170c116b3e"
|
||||
integrity sha512-Lv65Btwv9W4J9pyODI6EWpdnhfvrve/us5h1WspW8B2Fb0366REPtY3hX7ounk1CkV/TBjWCEvCBBbYbmV0qCA==
|
||||
|
||||
esbuild@^0.25.0:
|
||||
version "0.25.6"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.6.tgz#9b82a3db2fa131aec069ab040fd57ed0a880cdcd"
|
||||
integrity sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==
|
||||
optionalDependencies:
|
||||
"@esbuild/aix-ppc64" "0.25.6"
|
||||
"@esbuild/android-arm" "0.25.6"
|
||||
"@esbuild/android-arm64" "0.25.6"
|
||||
"@esbuild/android-x64" "0.25.6"
|
||||
"@esbuild/darwin-arm64" "0.25.6"
|
||||
"@esbuild/darwin-x64" "0.25.6"
|
||||
"@esbuild/freebsd-arm64" "0.25.6"
|
||||
"@esbuild/freebsd-x64" "0.25.6"
|
||||
"@esbuild/linux-arm" "0.25.6"
|
||||
"@esbuild/linux-arm64" "0.25.6"
|
||||
"@esbuild/linux-ia32" "0.25.6"
|
||||
"@esbuild/linux-loong64" "0.25.6"
|
||||
"@esbuild/linux-mips64el" "0.25.6"
|
||||
"@esbuild/linux-ppc64" "0.25.6"
|
||||
"@esbuild/linux-riscv64" "0.25.6"
|
||||
"@esbuild/linux-s390x" "0.25.6"
|
||||
"@esbuild/linux-x64" "0.25.6"
|
||||
"@esbuild/netbsd-arm64" "0.25.6"
|
||||
"@esbuild/netbsd-x64" "0.25.6"
|
||||
"@esbuild/openbsd-arm64" "0.25.6"
|
||||
"@esbuild/openbsd-x64" "0.25.6"
|
||||
"@esbuild/openharmony-arm64" "0.25.6"
|
||||
"@esbuild/sunos-x64" "0.25.6"
|
||||
"@esbuild/win32-arm64" "0.25.6"
|
||||
"@esbuild/win32-ia32" "0.25.6"
|
||||
"@esbuild/win32-x64" "0.25.6"
|
||||
|
||||
escalade@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
|
||||
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
|
||||
|
||||
fdir@^6.4.4, fdir@^6.4.6:
|
||||
version "6.4.6"
|
||||
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.6.tgz#2b268c0232697063111bbf3f64810a2a741ba281"
|
||||
integrity sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==
|
||||
|
||||
fsevents@~2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||
|
||||
fsevents@~2.3.3:
|
||||
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==
|
||||
|
||||
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@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d"
|
||||
integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
|
||||
|
||||
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==
|
||||
|
||||
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"
|
||||
|
||||
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==
|
||||
|
||||
ms@^2.1.3:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
nanoid@^3.3.11:
|
||||
version "3.3.11"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b"
|
||||
integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==
|
||||
|
||||
node-releases@^2.0.19:
|
||||
version "2.0.19"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314"
|
||||
integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==
|
||||
|
||||
picocolors@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
|
||||
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
|
||||
|
||||
picomatch@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab"
|
||||
integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
|
||||
|
||||
postcss@^8.5.6:
|
||||
version "8.5.6"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c"
|
||||
integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==
|
||||
dependencies:
|
||||
nanoid "^3.3.11"
|
||||
picocolors "^1.1.1"
|
||||
source-map-js "^1.2.1"
|
||||
|
||||
react-dom@19.0.0:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57"
|
||||
integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==
|
||||
dependencies:
|
||||
scheduler "^0.25.0"
|
||||
|
||||
react-refresh@^0.17.0:
|
||||
version "0.17.0"
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.17.0.tgz#b7e579c3657f23d04eccbe4ad2e58a8ed51e7e53"
|
||||
integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==
|
||||
|
||||
react@19.0.0:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd"
|
||||
integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
|
||||
|
||||
rollup@^4.40.0:
|
||||
version "4.44.2"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.44.2.tgz#faedb27cb2aa6742530c39668092eecbaf78c488"
|
||||
integrity sha512-PVoapzTwSEcelaWGth3uR66u7ZRo6qhPHc0f2uRO9fX6XDVNrIiGYS0Pj9+R8yIIYSD/mCx2b16Ws9itljKSPg==
|
||||
dependencies:
|
||||
"@types/estree" "1.0.8"
|
||||
optionalDependencies:
|
||||
"@rollup/rollup-android-arm-eabi" "4.44.2"
|
||||
"@rollup/rollup-android-arm64" "4.44.2"
|
||||
"@rollup/rollup-darwin-arm64" "4.44.2"
|
||||
"@rollup/rollup-darwin-x64" "4.44.2"
|
||||
"@rollup/rollup-freebsd-arm64" "4.44.2"
|
||||
"@rollup/rollup-freebsd-x64" "4.44.2"
|
||||
"@rollup/rollup-linux-arm-gnueabihf" "4.44.2"
|
||||
"@rollup/rollup-linux-arm-musleabihf" "4.44.2"
|
||||
"@rollup/rollup-linux-arm64-gnu" "4.44.2"
|
||||
"@rollup/rollup-linux-arm64-musl" "4.44.2"
|
||||
"@rollup/rollup-linux-loongarch64-gnu" "4.44.2"
|
||||
"@rollup/rollup-linux-powerpc64le-gnu" "4.44.2"
|
||||
"@rollup/rollup-linux-riscv64-gnu" "4.44.2"
|
||||
"@rollup/rollup-linux-riscv64-musl" "4.44.2"
|
||||
"@rollup/rollup-linux-s390x-gnu" "4.44.2"
|
||||
"@rollup/rollup-linux-x64-gnu" "4.44.2"
|
||||
"@rollup/rollup-linux-x64-musl" "4.44.2"
|
||||
"@rollup/rollup-win32-arm64-msvc" "4.44.2"
|
||||
"@rollup/rollup-win32-ia32-msvc" "4.44.2"
|
||||
"@rollup/rollup-win32-x64-msvc" "4.44.2"
|
||||
fsevents "~2.3.2"
|
||||
|
||||
scheduler@^0.25.0:
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015"
|
||||
integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==
|
||||
|
||||
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.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
|
||||
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
|
||||
|
||||
tinyglobby@^0.2.14:
|
||||
version "0.2.14"
|
||||
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d"
|
||||
integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==
|
||||
dependencies:
|
||||
fdir "^6.4.4"
|
||||
picomatch "^4.0.2"
|
||||
|
||||
typescript@5.8.3:
|
||||
version "5.8.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"
|
||||
integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==
|
||||
|
||||
update-browserslist-db@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420"
|
||||
integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==
|
||||
dependencies:
|
||||
escalade "^3.2.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
vite@7.0.4:
|
||||
version "7.0.4"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-7.0.4.tgz#481204416277cfa7c93384c55984475c4276b18f"
|
||||
integrity sha512-SkaSguuS7nnmV7mfJ8l81JGBFV7Gvzp8IzgE8A8t23+AxuNX61Q5H1Tpz5efduSN7NHC8nQXD3sKQKZAu5mNEA==
|
||||
dependencies:
|
||||
esbuild "^0.25.0"
|
||||
fdir "^6.4.6"
|
||||
picomatch "^4.0.2"
|
||||
postcss "^8.5.6"
|
||||
rollup "^4.40.0"
|
||||
tinyglobby "^0.2.14"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.3"
|
||||
|
||||
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