From c31366c8220498d0b59fe548760b8750c546afa7 Mon Sep 17 00:00:00 2001 From: Mar Date: Mon, 29 Jul 2024 21:27:25 +0200 Subject: [PATCH 1/4] YES --- src/main.rs | 53 +++++++++++++++++++++++++++++++++--------- src/requestresponse.rs | 5 ++-- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index b908608..f36d6c9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,16 +7,18 @@ use std::fs::File; use std::path::PathBuf; use std::{fs, process}; - +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; use actix_web::web::Data; use actix_web::{App, HttpServer}; use colored::Colorize; +use futures::join; #[allow(unused_imports)] use log::info; use log::LevelFilter; use log::{debug, error}; use simplelog::{ColorChoice, CombinedLogger, TermLogger, TerminalMode, WriteLogger}; -use tokio::sync::Mutex; +use tokio::sync::{Mutex, MutexGuard}; use crate::config::{CynthiaConf, SceneCollectionTrait}; use crate::files::CynthiaCache; @@ -28,8 +30,10 @@ mod publications; mod renders; mod requestresponse; mod tell; +mod externalpluginservers; +// mod jsrun; -pub struct LogSets { +struct LogSets { pub file_loglevel: LevelFilter, pub term_loglevel: LevelFilter, pub logfile: PathBuf, @@ -40,6 +44,8 @@ pub struct LogSets { struct ServerContext { config: CynthiaConf, cache: CynthiaCache, + request_count: u64, + start_time: u128, } #[tokio::main] @@ -109,8 +115,7 @@ async fn main() { "cynthiapluginmanifest.json".bright_green(),); process::exit(0); } - "start" => start().await, - _ => start().await, + "start" | _ => start().await, } } async fn start() { @@ -234,9 +239,12 @@ async fn start() { ]) .unwrap(); use crate::config::CynthiaConfig; + // Initialise context let server_context: ServerContext = ServerContext { config: config.hard_clone(), cache: vec![], + request_count: 0, + start_time: 0, }; let _ = &server_context.tell(format!( "Logging to {}", @@ -247,10 +255,13 @@ async fn start() { .to_string_lossy() .replace("\\\\?\\", "") )); - let server_context_: Data> = Data::new(Mutex::new(server_context)); + let server_context_arc_mutex: Arc> = Arc::new(Mutex::new(server_context)); + let server_context_data: Data>> = Data::new(server_context_arc_mutex.clone()); use requestresponse::serve; let main_server = - match HttpServer::new(move || App::new().service(serve).app_data(server_context_.clone())) + match HttpServer::new(move || { + App::new().service(serve).app_data(server_context_data.clone()) + }) .bind(("localhost", config.port)) { Ok(o) => { @@ -266,11 +277,31 @@ async fn start() { } } .run(); - let _ = futures::join!(main_server, close()); + let _ = join!(main_server, close(server_context_arc_mutex.clone()), start_timer(server_context_arc_mutex.clone())); +} +async fn start_timer(server_context_mutex: Arc>) { + let mut server_context: MutexGuard = server_context_mutex.lock().await; + server_context.start_time = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis(); } -async fn close() { +async fn close( + server_context_mutex: Arc> +) { let _ = tokio::signal::ctrl_c().await; - println!("\n\n\nBye!\n"); + let server_context: MutexGuard = server_context_mutex.lock().await; + let total_run_time = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() + - server_context.start_time; + let total_run_time_locale = chrono::Duration::milliseconds(total_run_time as i64); + let run_time_hours = total_run_time_locale.num_hours(); + let run_time_minutes = total_run_time_locale.num_minutes() - (total_run_time_locale.num_hours() * 60); + let run_time_seconds = total_run_time_locale.num_seconds() - (total_run_time_locale.num_minutes() * 60); + let run_time_string = format!("{}h {}m {}s", run_time_hours, run_time_minutes, run_time_seconds); + server_context.tell(format!("Closing:\n\n\n\nBye! I served {} requests in this run of {}!\n", server_context.request_count, run_time_string)); println!("{}", horizline().bright_purple()); process::exit(0); -} +} \ No newline at end of file diff --git a/src/requestresponse.rs b/src/requestresponse.rs index c3e4be2..1ac12dc 100644 --- a/src/requestresponse.rs +++ b/src/requestresponse.rs @@ -3,7 +3,7 @@ * * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. */ - +use std::sync::Arc; use crate::renders::render_from_pgid; use crate::{renders, ServerContext}; use actix_web::web::Data; @@ -14,10 +14,11 @@ use tokio::sync::{Mutex, MutexGuard}; #[get("/{a:.*}")] #[doc = r"Serves pages included in CynthiaConfig, or a default page if not found."] pub(crate) async fn serve( - server_context_mutex: Data>, + server_context_mutex: Data>>, req: HttpRequest, ) -> impl Responder { let mut server_context: MutexGuard = server_context_mutex.lock().await; + server_context.request_count += 1; let page_id = req.match_info().get("a").unwrap_or("root"); match renders::check_pgid(page_id.to_string(), &server_context) { renders::PGIDCheckResponse::Ok => { From bdb055eb04afe1aa0de0f9c33bcbe42a3f8956a8 Mon Sep 17 00:00:00 2001 From: Mar Date: Mon, 29 Jul 2024 23:00:00 +0200 Subject: [PATCH 2/4] Have tested around a bit. Will just commit this to be sure but this should not be on main branch lol --- Cargo.lock | 7 +++++ Cargo.toml | 2 ++ src-js/main.js | 37 +++++++++++++++++++++++ src/externalpluginservers.rs | 57 ++++++++++++++++++++++++++++++++++++ src/jsrun.rs | 6 ++-- src/main.rs | 5 ++-- src/renders.rs | 10 +++++++ 7 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 src-js/main.js create mode 100644 src/externalpluginservers.rs diff --git a/Cargo.lock b/Cargo.lock index 9134f2b..cc1145c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -884,6 +884,7 @@ dependencies = [ "futures", "handlebars", "indicatif", + "interactive_process", "jsonc-parser", "log", "markdown", @@ -1656,6 +1657,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "interactive_process" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb1a3c097cfdd0dc4bd03143a587b8cd44b492d763c768b06f7dfecaad7eeda4" + [[package]] name = "intrusive-collections" version = "0.9.6" diff --git a/Cargo.toml b/Cargo.toml index d9f4df0..1066f44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ strip-ansi-escapes = "0.2.0" tokio = { version = "1.38.0", features = [ "rt", "rt-multi-thread", + "process", "macros", "time", ] } @@ -46,3 +47,4 @@ termsize = "0.1" async-std = "1.12.0" rand = "0.8.5" reqwest = { version = "0.12.5", features = ["blocking"] } +interactive_process = "0.1.3" diff --git a/src-js/main.js b/src-js/main.js new file mode 100644 index 0000000..f1a237d --- /dev/null +++ b/src-js/main.js @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, MLC 'Strawmelonjuice' Bloeiman + * + * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. + */ + +console.log(` +Dit wordt gewoon naar de console geschreven. +Maar dit: +send: { +send: "test": "Wat de fuck", +send: "geel": [ +send: "verf", "krijt", "verf" +send: ] +send: } +Is als het goed is nu een struct. +`); +console.log(` +En dit is weer gewoon json. + { + "test": "Wat de fuck", + "geel": [ + "verf", "krijt", "verf" + ] + } +`); +console.log("En nu in stukjes:"); +console.log(` +send: { +send: "test": "Wat de fuck", +`); +console.log("send: \"geel\": [") +console.log(` +send: "verf", "krijt", "verf" +send: ] +send: }`); +console.log("Ziezo, in elkaar gezet!"); \ No newline at end of file diff --git a/src/externalpluginservers.rs b/src/externalpluginservers.rs new file mode 100644 index 0000000..8535b1d --- /dev/null +++ b/src/externalpluginservers.rs @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024, MLC 'Strawmelonjuice' Bloeiman + * + * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. + */ + +// Some plugins in Cynthia v2 served assets and pages over their own servers. These would be "proxied" by Cynthia. +// That functionality was derived from Cynthia v0/typescript, which would just hook those plugins onto the main +// server without requiring plugins to be written in Rust. +// This module will be a testing ground. V2 was unreliable and had a lot of issues, especially because it didn't keep the servers attached. It just let them run. +// This module will be a testing ground for a new system that will be more reliable and more secure. + +use interactive_process::InteractiveProcess; +use serde_json::from_str; +use std::process::Command; +use std::sync::{Arc, Mutex}; +#[derive(Debug, serde::Deserialize)] +struct Testje { + test: String, + geel: Vec, +} + +pub(crate) async fn main() { + let mut r = Command::new("node"); + r.arg("../src-js/main.js"); + let p = Arc::new(Mutex::new(String::new())); + let mut proc = InteractiveProcess::new(&mut r, move |line| { + let y = p.clone(); + match line { + Ok(o) => { + if o.starts_with("send: ") { + let l = o.split("send: ").collect::>()[1]; + let mut z = y.lock().unwrap(); + z.push_str(l); + let q = from_str::(z.as_str()); + match q { + Ok(o) => { + println!("{:#?}", o); + z.clear(); + } + _ => {} + } + } else { + if o.replace("\n", "").is_empty() { + // Just wait for the next line lol + } else { + let mut z = y.lock().unwrap(); + z.clear(); + println!("{}", o); + } + } + } + _ => {} + } + }) + .unwrap(); +} diff --git a/src/jsrun.rs b/src/jsrun.rs index 77a23d1..6cd874a 100644 --- a/src/jsrun.rs +++ b/src/jsrun.rs @@ -4,7 +4,7 @@ * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. */ -use boa_engine::{Context, JsResult, Source}; +use boa_engine::{Context, JsResult, JsValue, Source}; #[test] fn test() { println!( @@ -45,9 +45,9 @@ JSON.stringify(result); let mut context = Context::default(); // Parse the source code - context.module_loader() + let _ = context.module_loader(); let resultstr = context.eval(Source::from_bytes(js_code))?; - let resultstring = format!("{}", &resultstr.display()).clone(); + let resultstring: String = format!("{}", &JsValue::display(&resultstr)).clone(); let resultjson = { let mut o = resultstring.chars(); o.next(); diff --git a/src/main.rs b/src/main.rs index f36d6c9..1086f08 100644 --- a/src/main.rs +++ b/src/main.rs @@ -277,7 +277,7 @@ async fn start() { } } .run(); - let _ = join!(main_server, close(server_context_arc_mutex.clone()), start_timer(server_context_arc_mutex.clone())); + let _ = join!(main_server, close(server_context_arc_mutex.clone()), start_timer(server_context_arc_mutex.clone()), externalpluginservers::main()); } async fn start_timer(server_context_mutex: Arc>) { let mut server_context: MutexGuard = server_context_mutex.lock().await; @@ -301,7 +301,8 @@ async fn close( let run_time_minutes = total_run_time_locale.num_minutes() - (total_run_time_locale.num_hours() * 60); let run_time_seconds = total_run_time_locale.num_seconds() - (total_run_time_locale.num_minutes() * 60); let run_time_string = format!("{}h {}m {}s", run_time_hours, run_time_minutes, run_time_seconds); - server_context.tell(format!("Closing:\n\n\n\nBye! I served {} requests in this run of {}!\n", server_context.request_count, run_time_string)); + let s = if server_context.request_count == 1 { "" } else { "s" }; + server_context.tell(format!("Closing:\n\n\n\nBye! I served {} request{s} in this run of {}!\n", server_context.request_count, run_time_string)); println!("{}", horizline().bright_purple()); process::exit(0); } \ No newline at end of file diff --git a/src/renders.rs b/src/renders.rs index 5a767cd..b0e71d3 100644 --- a/src/renders.rs +++ b/src/renders.rs @@ -103,6 +103,15 @@ pub(crate) async fn render_from_pgid(pgid: String, config: CynthiaConfClone) -> } } +/// This struct is a stripped down version of the Scene struct in the config module. +/// It stores only the necessary data for rendering a single publication. +struct PublicationScene { + name: String, + template: String, + stylesheet: Option, + script: Option, +} + mod in_renderer { use crate::{ config::{CynthiaConfig, Scene, SceneCollectionTrait}, @@ -116,6 +125,7 @@ mod in_renderer { config: CynthiaConfClone, ) -> RenderrerResponse { let scene = fetch_scene(publication.clone(), config.clone()); + if scene.is_none() { error!("No scene found for publication."); return RenderrerResponse::Error; From 12ac1c59e41dcc29bb9fdcaa6b82af50b9836af1 Mon Sep 17 00:00:00 2001 From: Mar Date: Tue, 30 Jul 2024 02:19:15 +0200 Subject: [PATCH 3/4] Wdym impulsive? --- .gitignore | 1 - Cargo.toml | 4 + bananen.json | 138 - changelog.md | 56 - clean_config/Cynthia.toml | 33 - cynthiapluginmanifest.json | 14 - package-lock.json | 2388 +++++++++++++++++ package.json | 28 + source/Dash/postcss.config.js | 6 + source/Dash/tailwind.config.js | 38 + {src => source/Main/src}/config.rs | 31 +- {src => source/Main/src}/dash.rs | 0 source/Main/src/externalpluginservers.rs | 103 + {src => source/Main/src}/files.rs | 21 +- {src => source/Main/src}/jsrun.rs | 0 {src => source/Main/src}/jsruntime.rs | 0 {src => source/Main/src}/main.rs | 16 +- {src => source/Main/src}/publications.rs | 0 {src => source/Main/src}/renders.rs | 0 {src => source/Main/src}/requestresponse.rs | 0 {src => source/Main/src}/tell.rs | 0 .../node-plugin-api/package.json | 11 + .../node-plugin-runner/src/main.ts | 30 + .../docs}/configuration/Cynthia.toml.md | 0 .../configuration/Cynthia.toml/scenes.md | 0 .../docs}/configuration/published.jsonc.md | 0 .../published.jsonc/object-content.md | 0 .../published.jsonc/object-dates.md | 0 {docs => source/docs}/features.md | 0 src-js/main.js | 37 - src/externalpluginservers.rs | 57 - tsconfig.json | 22 + 32 files changed, 2690 insertions(+), 344 deletions(-) delete mode 100644 bananen.json delete mode 100644 changelog.md delete mode 100644 clean_config/Cynthia.toml delete mode 100644 cynthiapluginmanifest.json create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 source/Dash/postcss.config.js create mode 100644 source/Dash/tailwind.config.js rename {src => source/Main/src}/config.rs (92%) rename {src => source/Main/src}/dash.rs (100%) create mode 100644 source/Main/src/externalpluginservers.rs rename {src => source/Main/src}/files.rs (82%) rename {src => source/Main/src}/jsrun.rs (100%) rename {src => source/Main/src}/jsruntime.rs (100%) rename {src => source/Main/src}/main.rs (95%) rename {src => source/Main/src}/publications.rs (100%) rename {src => source/Main/src}/renders.rs (100%) rename {src => source/Main/src}/requestresponse.rs (100%) rename {src => source/Main/src}/tell.rs (100%) create mode 100644 source/Plugin-runners/node-plugin-api/package.json create mode 100644 source/Plugin-runners/node-plugin-runner/src/main.ts rename {docs => source/docs}/configuration/Cynthia.toml.md (100%) rename {docs => source/docs}/configuration/Cynthia.toml/scenes.md (100%) rename {docs => source/docs}/configuration/published.jsonc.md (100%) rename {docs => source/docs}/configuration/published.jsonc/object-content.md (100%) rename {docs => source/docs}/configuration/published.jsonc/object-dates.md (100%) rename {docs => source/docs}/features.md (100%) delete mode 100644 src-js/main.js delete mode 100644 src/externalpluginservers.rs create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index e5e4735..712c565 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ pnpm-lock.yaml /GETTINGSTARTED.MD /cynthiapmanifest.json src/client.js -/plugins/ # Ignore editor files /.idea/ diff --git a/Cargo.toml b/Cargo.toml index 1066f44..b9810b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,10 @@ edition = "2021" license = "AGPL-3.0-only" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[[bin]] +name = "cynthiaweb" +path = "./Main/src/main.rs" + [dependencies] futures = "0.3.30" diff --git a/bananen.json b/bananen.json deleted file mode 100644 index 2d8fee5..0000000 --- a/bananen.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "main": { - "bananen_version": "0.1.8", - "bananendata_version": 3 - }, - "config": { - "changelogfile": "changelog.md", - "rollingrelease": false, - "customisation": { - "log_name": "Changelog", - "released_name": "Releases", - "unreleased_name": "Unreleased changes", - "changetypes": { - "addition": { - "translation": "Addition", - "color": "#336600" - }, - "removal": { - "translation": "Removal", - "color": "#ff0000" - }, - "update": { - "translation": "Update", - "color": "#0033cc" - }, - "fix": { - "translation": "Fix", - "color": "#9900cc" - } - } - } - }, - "saved_changes": { - "unreleased": [], - "released": [ - { - "name": "2.1.4-alpha.0.1", - "changes": [ - { - "contents": "adding a plugin would attempt to remove it instead", - "type": 3, - "breaking": false - } - ] - }, - { - "name": "2.1.4-alpha.0.0", - "changes": [ - { - "contents": "The long awaited file logging feature!", - "type": 1, - "breaking": false - } - ] - }, - { - "name": "2.1.3-alpha.0.0", - "changes": [ - { - "contents": "404 pages can now be configured", - "type": 1, - "breaking": false - } - ] - }, - { - "name": "2.1.2-alpha.0.1", - "changes": [ - { - "contents": "Several bugs that could break Cynthia entirely", - "type": 3, - "breaking": false - } - ] - }, - { - "name": "2.1.2-alpha.0.0", - "changes": [ - { - "contents": "PM remove is now a valid subcommand", - "type": 1, - "breaking": false - }, - { - "contents": "Bug that caused successful requests to be ignored", - "type": 3, - "breaking": false - }, - { - "contents": "Extra support for metatags", - "type": 1, - "breaking": false - } - ] - }, - { - "name": "2.1.0-alpha.0.0", - "changes": [ - { - "contents": "Enhanced some HTML-grammar Cynthia was generating.", - "type": 2, - "breaking": false - }, - { - "contents": "Switching from `.env` to `Cynthia.toml`.", - "type": 2, - "breaking": true - } - ] - }, - { - "name": "Past changes", - "changes": [ - { - "contents": "Rewriting CynthiaCMS to Rust, to enhance user-friendlyness, a division of codebases and compatibility.", - "type": 2, - "breaking": true - }, - { - "contents": "Feature parity with TS version completed, plugin system 2.0 implemented.", - "type": 2, - "breaking": true - }, - { - "contents": "Override for showing page info sidebar, on either mode or post.", - "type": 1, - "breaking": false - }, - { - "contents": "Some issues with plugins that modified content.", - "type": 3, - "breaking": false - } - ] - } - ] - } -} \ No newline at end of file diff --git a/changelog.md b/changelog.md deleted file mode 100644 index 354c27f..0000000 --- a/changelog.md +++ /dev/null @@ -1,56 +0,0 @@ - -# Changelog - - -## Unreleased changes - -No unreleased changes. - -## Releases - - - -### 2.1.4-alpha.0.1 -- **Fix**: adding a plugin would attempt to remove it instead - - -### 2.1.4-alpha.0.0 -- **Addition**: The long awaited file logging feature! - - -### 2.1.3-alpha.0.0 -- **Addition**: 404 pages can now be configured - - -### 2.1.2-alpha.0.1 -- **Fix**: Several bugs that could break Cynthia entirely - - -### 2.1.2-alpha.0.0 -- **Addition**: Extra support for metatags - -- **Fix**: Bug that caused successful requests to be ignored - -- **Addition**: PM remove is now a valid subcommand - - -### 2.1.0-alpha.0.0 -- BREAKING! **Update**: Switching from `.env` to `Cynthia.toml`. - -- **Update**: Enhanced some HTML-grammar Cynthia was generating. - - -### Past changes -- **Fix**: Some issues with plugins that modified content. - -- **Addition**: Override for showing page info sidebar, on either mode or post. - -- BREAKING! **Update**: Feature parity with TS version completed, plugin system 2.0 implemented. - -- BREAKING! **Update**: Rewriting CynthiaCMS to Rust, to enhance user-friendlyness, a division of codebases and compatibility. - - -
- -This file was auto generated by [Bananen! 🍌](https://github.com/strawmelonjuice/bananen/) `v0.1.8` -. \ No newline at end of file diff --git a/clean_config/Cynthia.toml b/clean_config/Cynthia.toml deleted file mode 100644 index 1886bdb..0000000 --- a/clean_config/Cynthia.toml +++ /dev/null @@ -1,33 +0,0 @@ -# The port on which Cynthia hosts, since Cynthia was designed to be reverse-proxied, this port is usually higher than 1000. -PORT = 3000 -[cache] -# These rules are set for a reason: The higher they are set, the less requests we have to do to Node, external servers, etc. -# High caching lifetimes can speed up Cynthia a whole lot, so think wisely before you lower any of these numbers! -[cache.lifetimes] - -# How long (in seconds) to cache a CSS file after having minified and served it. -stylesheets = 72000 - -# How long (in seconds) to cache a JS file after having minified and served it. -javascript = 1200 - -# How long (in seconds) to cache an external output after having used it. -forwarded = 1600 - -# How long should a fully-ready-to-be-served page be cached? -served = 50 - -# Generator rules set how Cynthia generates web pages. -[generator] -site-baseurl = "" -og-site-name = "My Cynthia Site!" -[generator.meta] - -# Enables or disables pagetags in HTML metatags, these are officially supposed to be good for finding a website, but have been known to -# get nerfed by google, considering them spam. -enable-tags = false - -[logs] -file-loglevel = 3 -console-loglevel = 2 -file = "cynthia.log" diff --git a/cynthiapluginmanifest.json b/cynthiapluginmanifest.json deleted file mode 100644 index bb188a8..0000000 --- a/cynthiapluginmanifest.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "id": "hlimg", - "version": "latest" - }, - { - "id": "gfonts", - "version": "latest" - }, - { - "id": "git-pull", - "version": "latest" - } -] diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1d30c9a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2388 @@ +{ + "name": "CynthiaWebsiteEngine", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "@biomejs/biome": "latest", + "autoprefixer": "latest", + "clean-css-cli": "4", + "postcss": "latest", + "postcss-cli": "^11.0.0", + "tailwindcss": "latest", + "terser": "latest", + "typescript": "^5.0.0" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@biomejs/biome": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.8.3.tgz", + "integrity": "sha512-/uUV3MV+vyAczO+vKrPdOW0Iaet7UnJMU4bNMinggGJTAnBPjCoLEYcyYtYHNnUNYlv4xZMH6hVIQCAozq8d5w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "1.8.3", + "@biomejs/cli-darwin-x64": "1.8.3", + "@biomejs/cli-linux-arm64": "1.8.3", + "@biomejs/cli-linux-arm64-musl": "1.8.3", + "@biomejs/cli-linux-x64": "1.8.3", + "@biomejs/cli-linux-x64-musl": "1.8.3", + "@biomejs/cli-win32-arm64": "1.8.3", + "@biomejs/cli-win32-x64": "1.8.3" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.8.3.tgz", + "integrity": "sha512-9DYOjclFpKrH/m1Oz75SSExR8VKvNSSsLnVIqdnKexj6NwmiMlKk94Wa1kZEdv6MCOHGHgyyoV57Cw8WzL5n3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.8.3.tgz", + "integrity": "sha512-UeW44L/AtbmOF7KXLCoM+9PSgPo0IDcyEUfIoOXYeANaNXXf9mLUwV1GeF2OWjyic5zj6CnAJ9uzk2LT3v/wAw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.8.3.tgz", + "integrity": "sha512-fed2ji8s+I/m8upWpTJGanqiJ0rnlHOK3DdxsyVLZQ8ClY6qLuPc9uehCREBifRJLl/iJyQpHIRufLDeotsPtw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.8.3.tgz", + "integrity": "sha512-9yjUfOFN7wrYsXt/T/gEWfvVxKlnh3yBpnScw98IF+oOeCYb5/b/+K7YNqKROV2i1DlMjg9g/EcN9wvj+NkMuQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.8.3.tgz", + "integrity": "sha512-I8G2QmuE1teISyT8ie1HXsjFRz9L1m5n83U1O6m30Kw+kPMPSKjag6QGUn+sXT8V+XWIZxFFBoTDEDZW2KPDDw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.8.3.tgz", + "integrity": "sha512-UHrGJX7PrKMKzPGoEsooKC9jXJMa28TUSMjcIlbDnIO4EAavCoVmNQaIuUSH0Ls2mpGMwUIf+aZJv657zfWWjA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.8.3.tgz", + "integrity": "sha512-J+Hu9WvrBevfy06eU1Na0lpc7uR9tibm9maHynLIoAjLZpQU3IW+OKHUtyL8p6/3pT2Ju5t5emReeIS2SAxhkQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.8.3.tgz", + "integrity": "sha512-/PJ59vA1pnQeKahemaQf4Nyj7IKUvGQSc3Ze1uIGi+Wvr1xF7rGobSrAAG01T/gUDG21vkDsZYM03NAmPiVkqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.4.19", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", + "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001599", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001643", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", + "integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/clean-css": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", + "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/clean-css-cli": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/clean-css-cli/-/clean-css-cli-4.3.0.tgz", + "integrity": "sha512-8GHZfr+mG3zB/Lgqrr27qHBFsPSn0fyEI3f2rIZpxPxUbn2J6A8xyyeBRVTW8duDuXigN0s80vsXiXJOEFIO5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-css": "^4.2.1", + "commander": "2.x", + "glob": "7.x" + }, + "bin": { + "cleancss": "bin/cleancss" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.3.tgz", + "integrity": "sha512-QNdYSS5i8D9axWp/6XIezRObRHqaav/ur9z1VzCDUCH1XIFOr9WQk5xmgunhsTpjjgDy3oLxO/WMOVZlpUQrlA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.4.40", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz", + "integrity": "sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-cli": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-11.0.0.tgz", + "integrity": "sha512-xMITAI7M0u1yolVcXJ9XTZiO9aO49mcoKQy6pCDFdMh9kGqhzLVpWxeD/32M/QBmkhcGypZFFOLNLmIW4Pg4RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.3.0", + "dependency-graph": "^0.11.0", + "fs-extra": "^11.0.0", + "get-stdin": "^9.0.0", + "globby": "^14.0.0", + "picocolors": "^1.0.0", + "postcss-load-config": "^5.0.0", + "postcss-reporter": "^7.0.0", + "pretty-hrtime": "^1.0.3", + "read-cache": "^1.0.0", + "slash": "^5.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "postcss": "index.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-5.1.0.tgz", + "integrity": "sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1", + "yaml": "^2.4.2" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-reporter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.1.0.tgz", + "integrity": "sha512-/eoEylGWyy6/DOiMP5lmFRdmDKThqgn7D6hP2dXKJI/0rJSO1ADFNngZfDzxL0YAxFvws+Rtpuji1YIHj4mySA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "thenby": "^1.3.4" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", + "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.7.tgz", + "integrity": "sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tailwindcss/node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/terser": { + "version": "5.31.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz", + "integrity": "sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/thenby": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", + "integrity": "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..cbd3dc8 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "devDependencies": { + "tailwindcss": "latest", + "autoprefixer": "latest", + "postcss": "latest", + "terser": "latest", + "typescript": "^5.0.0", + "postcss-cli": "^11.0.0", + "@biomejs/biome": "latest", + "clean-css-cli": "4" + }, + "scripts": { + "build": "npm run build:deps && npm run build:rs", + "build:deps": "npm run build:css && npm run build:jsts && npm run minify", + "build:css-disabled": "postcss -o ./target/generated/css/main.css src-frontend/styles/main.pcss", + "build:css": "echo tailwind compilation is disabled.", + "build:jsts": "tsc", + "build:rs": "cargo build", + "format": "npm run format:rs && npm run format:ts && npm run minify:css", + "format:rs": "cargo fmt", + "format:ts": "npx biome format \"./src-frontend/ts/main.ts\" --write", + "minify": "echo minification is disabled.", + "minify-disabled": "npm run minify:js && npm run minify:css", + "minify:js": "npx terser src-frontend/js/prefetch.js > ./target/generated/js/prefetch.min.js && npx terser src-frontend/js/login.js > ./target/generated/js/login.min.js && npx terser src-frontend/js/login.js > ./target/generated/js/login.min.js && npx terser src-frontend/js/site-home.js > ./target/generated/js/site-home.min.js && npx terser src-frontend/js/site-index.js > ./target/generated/js/site-index.min.js && npx terser src-frontend/js/signup.js > ./target/generated/js/signup.min.js", + "minify:css": "npx cleancss -O1 specialComments:all --inline none ./target/generated/css/main.css > ./target/generated/css/main.min.css", + "start": "cargo run" + } +} diff --git a/source/Dash/postcss.config.js b/source/Dash/postcss.config.js new file mode 100644 index 0000000..e873f1a --- /dev/null +++ b/source/Dash/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/source/Dash/tailwind.config.js b/source/Dash/tailwind.config.js new file mode 100644 index 0000000..a350d61 --- /dev/null +++ b/source/Dash/tailwind.config.js @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024, MLC 'Strawmelonjuice' Bloeiman + * + * Licensed under the BSD 3-Clause License. See the LICENSE file for more info. + */ + +/** @type {import('tailwindcss').LuminaConfig} */ +module.exports = { + content: [ + "./src-frontend/**/*.{html,handlebars,js}", + "./target/generated/**/.{html,handlebars}", + "./src-backend/api_fe.rs", + ], + theme: { + fontFamily: { + sans: ["Josefin Sans", "Fira Sans", "sans-serif"], + serif: [], + }, + extend: { + colors: { + brown: { + 25: "#E9F7F6", + 50: "#fdf8f6", + 100: "#f2e8e5", + 200: "#eaddd7", + 300: "#e0cec7", + 400: "#d2bab0", + 500: "#bfa094", + 600: "#a18072", + 700: "#977669", + 800: "#846358", + 900: "#43302b", + }, + }, + }, + }, + plugins: [], +}; diff --git a/src/config.rs b/source/Main/src/config.rs similarity index 92% rename from src/config.rs rename to source/Main/src/config.rs index 3bec7db..d308fd6 100644 --- a/src/config.rs +++ b/source/Main/src/config.rs @@ -21,7 +21,23 @@ pub struct CynthiaConf { #[serde(alias = "Scenes")] #[serde(default = "c_emptyscenelist")] pub scenes: SceneCollection, + #[serde(alias = "Runtimes")] + #[serde(alias = "runners")] + #[serde(default)] + pub runtimes: Runtimes, +} +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub(crate) struct Runtimes { + pub(crate) node: String, +} +impl Default for Runtimes { + fn default() -> Self { + Runtimes { + node: String::from("bun"), + } + } } + pub(crate) type SceneCollection = Vec; pub(crate) trait SceneCollectionTrait { fn get_by_name(&self, name: &str) -> Option; @@ -71,6 +87,7 @@ pub struct CynthiaConfClone { pub generator: Generator, pub logs: Option, pub scenes: SceneCollection, + pub runtimes: Runtimes } impl CynthiaConfig for CynthiaConfClone { @@ -82,6 +99,7 @@ impl CynthiaConfig for CynthiaConfClone { generator: self.generator.clone(), logs: self.logs.clone(), scenes: self.scenes.clone(), + runtimes: self.runtimes.clone() } } fn clone(&self) -> CynthiaConfClone { @@ -92,32 +110,34 @@ impl CynthiaConfig for CynthiaConfClone { generator: self.generator.clone(), logs: self.logs.clone(), scenes: self.scenes.clone(), + runtimes: self.runtimes.clone() } } } impl CynthiaConfig for CynthiaConf { - fn clone(&self) -> CynthiaConfClone { - CynthiaConfClone { + fn hard_clone(&self) -> CynthiaConf { + CynthiaConf { port: self.port, cache: self.cache.clone(), pages: self.pages.clone(), generator: self.generator.clone(), logs: self.logs.clone(), scenes: self.scenes.clone(), + runtimes: self.runtimes.clone() } } - fn hard_clone(&self) -> CynthiaConf { - CynthiaConf { + fn clone(&self) -> CynthiaConfClone { + CynthiaConfClone { port: self.port, cache: self.cache.clone(), pages: self.pages.clone(), generator: self.generator.clone(), logs: self.logs.clone(), scenes: self.scenes.clone(), + runtimes: self.runtimes.clone() } } } -#[allow(unused)] pub trait CynthiaConfig { fn hard_clone(&self) -> CynthiaConf; fn clone(&self) -> CynthiaConfClone; @@ -132,6 +152,7 @@ impl CynthiaConf { generator: self.generator.clone(), logs: self.logs.clone(), scenes: self.scenes.clone(), + runtimes: self.runtimes.clone(), } } } diff --git a/src/dash.rs b/source/Main/src/dash.rs similarity index 100% rename from src/dash.rs rename to source/Main/src/dash.rs diff --git a/source/Main/src/externalpluginservers.rs b/source/Main/src/externalpluginservers.rs new file mode 100644 index 0000000..9dee1ff --- /dev/null +++ b/source/Main/src/externalpluginservers.rs @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024, MLC 'Strawmelonjuice' Bloeiman + * + * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. + */ + +// Some plugins in Cynthia v2 served assets and pages over their own servers. These would be "proxied" by Cynthia. +// That functionality was derived from Cynthia v0/typescript, which would just hook those plugins onto the main +// server without requiring plugins to be written in Rust. +// This module will be a testing ground. V2 was unreliable and had a lot of issues, especially because it didn't keep the servers attached. It just let them run. +// This module will be a testing ground for a new system that will be more reliable and more secure. +// More specifically: The plugins will attach to js again, but inside of a controlled environment. +pub(crate) struct EPSRequest { + pub(crate) id: u64, + pub(crate) command: String, +} +#[derive(Serialize, Deserialize, Debug)] +pub(crate) struct EPSResponse { + pub(crate) id: u64, + pub(crate) body: EPSResponseBody, +} +#[derive(Serialize, Deserialize, Debug)] +pub(crate) enum EPSResponseBody { + NoneOk, + Json(String), +// We'll add more types later, these will be very specific to the calls made by the server. +} + +use interactive_process::InteractiveProcess; +use serde_json::from_str; +use std::process::Command; +use std::sync::{Arc}; +use serde::{Deserialize, Serialize}; +use tokio::sync::mpsc::Receiver; +use crate::files::tempfolder; +use crate::ServerContext; + + +pub(crate) async fn main(_server_context_mutex: Arc>, mut eps_r: Receiver) { + let config_clone = { + // We need to clone the config because we can't hold the lock while we're in the tokio runtime. + let server_context = _server_context_mutex.lock().await; + server_context.config.clone() + }; + // We gotta write the javascript to a temporary file and then run it. + let jstempfolder = tempfolder().join("js"); + std::fs::create_dir_all(&jstempfolder).unwrap(); + let jsfile = include_bytes!("../target/generated/js/main.js"); + std::fs::write(jstempfolder.join("main.js"), jsfile).unwrap(); + // now we can run the javascript + let node_runtime: &str = config_clone.runtimes.node.as_ref(); + let mut r = Command::new(node_runtime); + r.arg(jstempfolder.join("main.js")); + let p = Arc::new(std::sync::Mutex::new(String::new())); + let mut proc = InteractiveProcess::new(&mut r, move |line| { + let y = p.clone(); + match line { + Ok(o) => { + if o.starts_with("send: ") { + let l = o.split("send: ").collect::>()[1]; + let mut z = y.lock().unwrap(); + z.push_str(l); + let q = from_str::(z.as_str()); + match q { + Ok(o) => { + println!("{:#?}", o); + z.clear(); + } + _ => {} + } + } else { + if o.replace("\n", "").is_empty() { + // Just wait for the next line lol + } else { + let mut z = y.lock().unwrap(); + z.clear(); + println!("{}", o); + } + } + } + _ => {} + } + }) + .unwrap(); + loop { + match eps_r.recv().await { + Some(r) => { + match r.command.as_str() { + "close" => { + proc.send("close").unwrap() + } + _ => {} + } + } + _ => {} + } + + } +} + +fn contact_eps() { + todo!() +} \ No newline at end of file diff --git a/src/files.rs b/source/Main/src/files.rs similarity index 82% rename from src/files.rs rename to source/Main/src/files.rs index 49b254a..374238f 100644 --- a/src/files.rs +++ b/source/Main/src/files.rs @@ -3,10 +3,12 @@ * * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. */ - +use std::fs; +use std::path::PathBuf; use crate::ServerContext; use log::{debug, trace}; use std::time::{SystemTime, UNIX_EPOCH}; +use normalize_path::NormalizePath; pub(super) type CynthiaCache = Vec; #[derive(Debug, Clone)] @@ -81,3 +83,20 @@ impl ServerContext { self.cache.iter().map(|x| x.content.len()).sum() } } +#[allow(dead_code)] +fn cachefolder() -> PathBuf { + let fl = tempfolder() + .join(format!("{}", std::process::id())) + .normalize(); + // logger(31, format!("Cache folder: {}", fl.display())); + fs::create_dir_all(&fl).unwrap(); + fl +} +pub(crate) fn tempfolder() -> PathBuf { + let fl = PathBuf::from("./.cynthiaTemp/") + .join(format!("{}", std::process::id())) + .normalize(); + // logger(31, format!("Cache folder: {}", fl.display())); + fs::create_dir_all(&fl).unwrap(); + fl +} \ No newline at end of file diff --git a/src/jsrun.rs b/source/Main/src/jsrun.rs similarity index 100% rename from src/jsrun.rs rename to source/Main/src/jsrun.rs diff --git a/src/jsruntime.rs b/source/Main/src/jsruntime.rs similarity index 100% rename from src/jsruntime.rs rename to source/Main/src/jsruntime.rs diff --git a/src/main.rs b/source/Main/src/main.rs similarity index 95% rename from src/main.rs rename to source/Main/src/main.rs index 1086f08..ed97e4f 100644 --- a/src/main.rs +++ b/source/Main/src/main.rs @@ -8,6 +8,7 @@ use std::fs::File; use std::path::PathBuf; use std::{fs, process}; use std::sync::Arc; +use std::sync::mpsc::Sender; use std::time::{SystemTime, UNIX_EPOCH}; use actix_web::web::Data; use actix_web::{App, HttpServer}; @@ -21,6 +22,7 @@ use simplelog::{ColorChoice, CombinedLogger, TermLogger, TerminalMode, WriteLogg use tokio::sync::{Mutex, MutexGuard}; use crate::config::{CynthiaConf, SceneCollectionTrait}; +use crate::externalpluginservers::EPSRequest; use crate::files::CynthiaCache; use crate::tell::horizline; @@ -39,13 +41,14 @@ struct LogSets { pub logfile: PathBuf, } -#[derive(Default, Debug)] +#[derive(Debug)] /// Server context, containing the configuration and cache. Also implements a `tell` method for easy logging. struct ServerContext { config: CynthiaConf, cache: CynthiaCache, request_count: u64, start_time: u128, + external_plugin_server: tokio::sync::mpsc::Sender, } #[tokio::main] @@ -239,12 +242,16 @@ async fn start() { ]) .unwrap(); use crate::config::CynthiaConfig; + + let (eps_s, eps_r) = tokio::sync::mpsc::channel::(100); + // Initialise context let server_context: ServerContext = ServerContext { config: config.hard_clone(), cache: vec![], request_count: 0, start_time: 0, + external_plugin_server: eps_s, }; let _ = &server_context.tell(format!( "Logging to {}", @@ -277,7 +284,7 @@ async fn start() { } } .run(); - let _ = join!(main_server, close(server_context_arc_mutex.clone()), start_timer(server_context_arc_mutex.clone()), externalpluginservers::main()); + let _ = join!(main_server, close(server_context_arc_mutex.clone()), start_timer(server_context_arc_mutex.clone()), externalpluginservers::main(server_context_arc_mutex.clone(), eps_r)); } async fn start_timer(server_context_mutex: Arc>) { let mut server_context: MutexGuard = server_context_mutex.lock().await; @@ -291,6 +298,11 @@ async fn close( ) { let _ = tokio::signal::ctrl_c().await; let server_context: MutexGuard = server_context_mutex.lock().await; + // Basically now that we block the main thread, we have all the time lol + server_context.external_plugin_server.send(EPSRequest { + id: 0, + command: "close".to_string(), + }).await.unwrap(); let total_run_time = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() diff --git a/src/publications.rs b/source/Main/src/publications.rs similarity index 100% rename from src/publications.rs rename to source/Main/src/publications.rs diff --git a/src/renders.rs b/source/Main/src/renders.rs similarity index 100% rename from src/renders.rs rename to source/Main/src/renders.rs diff --git a/src/requestresponse.rs b/source/Main/src/requestresponse.rs similarity index 100% rename from src/requestresponse.rs rename to source/Main/src/requestresponse.rs diff --git a/src/tell.rs b/source/Main/src/tell.rs similarity index 100% rename from src/tell.rs rename to source/Main/src/tell.rs diff --git a/source/Plugin-runners/node-plugin-api/package.json b/source/Plugin-runners/node-plugin-api/package.json new file mode 100644 index 0000000..46e3552 --- /dev/null +++ b/source/Plugin-runners/node-plugin-api/package.json @@ -0,0 +1,11 @@ +{ + "name": "cynthia-plugin-api", + "version": "1.0.0", + "description": "Contains some classes and functions to help you create CynthiaWeb plugins.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "MLC Bloeiman", + "license": "ISC" +} diff --git a/source/Plugin-runners/node-plugin-runner/src/main.ts b/source/Plugin-runners/node-plugin-runner/src/main.ts new file mode 100644 index 0000000..5dcec1b --- /dev/null +++ b/source/Plugin-runners/node-plugin-runner/src/main.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024, MLC 'Strawmelonjuice' Bloeiman + * + * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. + */ + +const cynthia = { + +} + +const cynthiabase = { + modifyOutputHTML: [ + (htmlin: string, cynthia) => { + // Make no changes. Return unchanged. + return htmlin; + }, + ], + modifyBodyHTML: [ + (htmlin: string) => { + // Make no changes. Return unchanged. + return htmlin; + }, + ], + requestOptions: [ + () => { + void expressapp; + }, + ], + LogReader: [(type: string, msg: string) => { }], +}; \ No newline at end of file diff --git a/docs/configuration/Cynthia.toml.md b/source/docs/configuration/Cynthia.toml.md similarity index 100% rename from docs/configuration/Cynthia.toml.md rename to source/docs/configuration/Cynthia.toml.md diff --git a/docs/configuration/Cynthia.toml/scenes.md b/source/docs/configuration/Cynthia.toml/scenes.md similarity index 100% rename from docs/configuration/Cynthia.toml/scenes.md rename to source/docs/configuration/Cynthia.toml/scenes.md diff --git a/docs/configuration/published.jsonc.md b/source/docs/configuration/published.jsonc.md similarity index 100% rename from docs/configuration/published.jsonc.md rename to source/docs/configuration/published.jsonc.md diff --git a/docs/configuration/published.jsonc/object-content.md b/source/docs/configuration/published.jsonc/object-content.md similarity index 100% rename from docs/configuration/published.jsonc/object-content.md rename to source/docs/configuration/published.jsonc/object-content.md diff --git a/docs/configuration/published.jsonc/object-dates.md b/source/docs/configuration/published.jsonc/object-dates.md similarity index 100% rename from docs/configuration/published.jsonc/object-dates.md rename to source/docs/configuration/published.jsonc/object-dates.md diff --git a/docs/features.md b/source/docs/features.md similarity index 100% rename from docs/features.md rename to source/docs/features.md diff --git a/src-js/main.js b/src-js/main.js deleted file mode 100644 index f1a237d..0000000 --- a/src-js/main.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2024, MLC 'Strawmelonjuice' Bloeiman - * - * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. - */ - -console.log(` -Dit wordt gewoon naar de console geschreven. -Maar dit: -send: { -send: "test": "Wat de fuck", -send: "geel": [ -send: "verf", "krijt", "verf" -send: ] -send: } -Is als het goed is nu een struct. -`); -console.log(` -En dit is weer gewoon json. - { - "test": "Wat de fuck", - "geel": [ - "verf", "krijt", "verf" - ] - } -`); -console.log("En nu in stukjes:"); -console.log(` -send: { -send: "test": "Wat de fuck", -`); -console.log("send: \"geel\": [") -console.log(` -send: "verf", "krijt", "verf" -send: ] -send: }`); -console.log("Ziezo, in elkaar gezet!"); \ No newline at end of file diff --git a/src/externalpluginservers.rs b/src/externalpluginservers.rs deleted file mode 100644 index 8535b1d..0000000 --- a/src/externalpluginservers.rs +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2024, MLC 'Strawmelonjuice' Bloeiman - * - * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. - */ - -// Some plugins in Cynthia v2 served assets and pages over their own servers. These would be "proxied" by Cynthia. -// That functionality was derived from Cynthia v0/typescript, which would just hook those plugins onto the main -// server without requiring plugins to be written in Rust. -// This module will be a testing ground. V2 was unreliable and had a lot of issues, especially because it didn't keep the servers attached. It just let them run. -// This module will be a testing ground for a new system that will be more reliable and more secure. - -use interactive_process::InteractiveProcess; -use serde_json::from_str; -use std::process::Command; -use std::sync::{Arc, Mutex}; -#[derive(Debug, serde::Deserialize)] -struct Testje { - test: String, - geel: Vec, -} - -pub(crate) async fn main() { - let mut r = Command::new("node"); - r.arg("../src-js/main.js"); - let p = Arc::new(Mutex::new(String::new())); - let mut proc = InteractiveProcess::new(&mut r, move |line| { - let y = p.clone(); - match line { - Ok(o) => { - if o.starts_with("send: ") { - let l = o.split("send: ").collect::>()[1]; - let mut z = y.lock().unwrap(); - z.push_str(l); - let q = from_str::(z.as_str()); - match q { - Ok(o) => { - println!("{:#?}", o); - z.clear(); - } - _ => {} - } - } else { - if o.replace("\n", "").is_empty() { - // Just wait for the next line lol - } else { - let mut z = y.lock().unwrap(); - z.clear(); - println!("{}", o); - } - } - } - _ => {} - } - }) - .unwrap(); -} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..636db2f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES5", + "lib": [ + "dom", + "ES2021", + "ES2023" + ], + "declaration": true, + "outDir": "./target/generated/js/", + "sourceMap": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "strict": true, + "noImplicitAny": false + }, + "exclude": [ + "./target/generated/js/" + ], + "include": ["./source/Plugin-runners/node-plugin-runner/src/", "./source/Plugin-runners/node-plugin-api/src"] +} From 0ef7f58f406c36232c191aa62e1af06613493920 Mon Sep 17 00:00:00 2001 From: Mar Date: Tue, 30 Jul 2024 18:52:42 +0200 Subject: [PATCH 4/4] Wdym impulsive? (pt 2) Shit works! --- Cargo.toml | 2 +- package-lock.json | 28 ++- package.json | 8 +- source/Main/src/config.rs | 12 +- source/Main/src/externalpluginservers.rs | 185 +++++++++++++++--- source/Main/src/files.rs | 8 +- source/Main/src/main.rs | 133 ++++++++----- source/Main/src/requestresponse.rs | 10 +- source/Main/src/tell.rs | 25 ++- source/Plugin-runners/node-plugin-api/main.ts | 85 ++++++++ .../node-plugin-api/package.json | 9 +- .../node-plugin-runner/src/main.ts | 65 +++--- tsconfig.json | 2 +- 13 files changed, 458 insertions(+), 114 deletions(-) create mode 100644 source/Plugin-runners/node-plugin-api/main.ts diff --git a/Cargo.toml b/Cargo.toml index b9810b9..03e2f65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ license = "AGPL-3.0-only" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [[bin]] name = "cynthiaweb" -path = "./Main/src/main.rs" +path = "./source/Main/src/main.rs" [dependencies] diff --git a/package-lock.json b/package-lock.json index 1d30c9a..fb08aa8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,8 +4,12 @@ "requires": true, "packages": { "": { + "dependencies": { + "cynthia-plugin-api": "file:source/Plugin-runners/node-plugin-api/" + }, "devDependencies": { "@biomejs/biome": "latest", + "@types/node": "latest", "autoprefixer": "latest", "clean-css-cli": "4", "postcss": "latest", @@ -421,6 +425,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@types/node": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.0.0.tgz", + "integrity": "sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.11.1" + } + }, "node_modules/acorn": { "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", @@ -774,6 +788,10 @@ "node": ">=4" } }, + "node_modules/cynthia-plugin-api": { + "resolved": "source/Plugin-runners/node-plugin-api", + "link": true + }, "node_modules/dependency-graph": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", @@ -2211,6 +2229,13 @@ "node": ">=14.17" } }, + "node_modules/undici-types": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.11.1.tgz", + "integrity": "sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ==", + "dev": true, + "license": "MIT" + }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", @@ -2383,6 +2408,7 @@ "engines": { "node": ">=12" } - } + }, + "source/Plugin-runners/node-plugin-api": {} } } diff --git a/package.json b/package.json index cbd3dc8..581a818 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,12 @@ "typescript": "^5.0.0", "postcss-cli": "^11.0.0", "@biomejs/biome": "latest", + "@types/node": "latest", "clean-css-cli": "4" }, + "dependencies": { + "cynthia-plugin-api": "file:source/Plugin-runners/node-plugin-api/" + }, "scripts": { "build": "npm run build:deps && npm run build:rs", "build:deps": "npm run build:css && npm run build:jsts && npm run minify", @@ -23,6 +27,6 @@ "minify-disabled": "npm run minify:js && npm run minify:css", "minify:js": "npx terser src-frontend/js/prefetch.js > ./target/generated/js/prefetch.min.js && npx terser src-frontend/js/login.js > ./target/generated/js/login.min.js && npx terser src-frontend/js/login.js > ./target/generated/js/login.min.js && npx terser src-frontend/js/site-home.js > ./target/generated/js/site-home.min.js && npx terser src-frontend/js/site-index.js > ./target/generated/js/site-index.min.js && npx terser src-frontend/js/signup.js > ./target/generated/js/signup.min.js", "minify:css": "npx cleancss -O1 specialComments:all --inline none ./target/generated/css/main.css > ./target/generated/css/main.min.css", - "start": "cargo run" + "start": "npm run build && cargo run" } -} +} \ No newline at end of file diff --git a/source/Main/src/config.rs b/source/Main/src/config.rs index d308fd6..deaf08e 100644 --- a/source/Main/src/config.rs +++ b/source/Main/src/config.rs @@ -87,7 +87,7 @@ pub struct CynthiaConfClone { pub generator: Generator, pub logs: Option, pub scenes: SceneCollection, - pub runtimes: Runtimes + pub runtimes: Runtimes, } impl CynthiaConfig for CynthiaConfClone { @@ -99,7 +99,7 @@ impl CynthiaConfig for CynthiaConfClone { generator: self.generator.clone(), logs: self.logs.clone(), scenes: self.scenes.clone(), - runtimes: self.runtimes.clone() + runtimes: self.runtimes.clone(), } } fn clone(&self) -> CynthiaConfClone { @@ -110,7 +110,7 @@ impl CynthiaConfig for CynthiaConfClone { generator: self.generator.clone(), logs: self.logs.clone(), scenes: self.scenes.clone(), - runtimes: self.runtimes.clone() + runtimes: self.runtimes.clone(), } } } @@ -123,7 +123,7 @@ impl CynthiaConfig for CynthiaConf { generator: self.generator.clone(), logs: self.logs.clone(), scenes: self.scenes.clone(), - runtimes: self.runtimes.clone() + runtimes: self.runtimes.clone(), } } fn clone(&self) -> CynthiaConfClone { @@ -134,7 +134,7 @@ impl CynthiaConfig for CynthiaConf { generator: self.generator.clone(), logs: self.logs.clone(), scenes: self.scenes.clone(), - runtimes: self.runtimes.clone() + runtimes: self.runtimes.clone(), } } } @@ -152,7 +152,7 @@ impl CynthiaConf { generator: self.generator.clone(), logs: self.logs.clone(), scenes: self.scenes.clone(), - runtimes: self.runtimes.clone(), + runtimes: self.runtimes.clone(), } } } diff --git a/source/Main/src/externalpluginservers.rs b/source/Main/src/externalpluginservers.rs index 9dee1ff..bd57dce 100644 --- a/source/Main/src/externalpluginservers.rs +++ b/source/Main/src/externalpluginservers.rs @@ -10,33 +10,53 @@ // This module will be a testing ground. V2 was unreliable and had a lot of issues, especially because it didn't keep the servers attached. It just let them run. // This module will be a testing ground for a new system that will be more reliable and more secure. // More specifically: The plugins will attach to js again, but inside of a controlled environment. + +#[derive(Serialize, Deserialize, Debug)] pub(crate) struct EPSRequest { - pub(crate) id: u64, - pub(crate) command: String, + id: EPSCommunicationsID, + pub(crate) body: EPSRequestBody, } #[derive(Serialize, Deserialize, Debug)] +#[serde(tag = "for")] +pub(crate) enum EPSRequestBody { + Close, + Test { test: String }, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] pub(crate) struct EPSResponse { - pub(crate) id: u64, + id: EPSCommunicationsID, pub(crate) body: EPSResponseBody, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(tag = "as")] pub(crate) enum EPSResponseBody { NoneOk, - Json(String), -// We'll add more types later, these will be very specific to the calls made by the server. + OkString { value: String }, + Json { value: String }, + Error { message: Option }, } +use crate::config::CynthiaConfig; +use crate::files::tempfolder; +use crate::{EPSCommunicationsID, ServerContext}; +use actix_web::web::Data; +use futures::FutureExt; use interactive_process::InteractiveProcess; +use log::debug; +use serde::{Deserialize, Serialize}; use serde_json::from_str; use std::process::Command; -use std::sync::{Arc}; -use serde::{Deserialize, Serialize}; +use std::sync::Arc; use tokio::sync::mpsc::Receiver; -use crate::files::tempfolder; -use crate::ServerContext; +use tokio::sync::Mutex; +pub(crate) async fn main( + _server_context_mutex: Arc>, + mut eps_r: Receiver, +) { + let rt = tokio::runtime::Runtime::new().unwrap(); -pub(crate) async fn main(_server_context_mutex: Arc>, mut eps_r: Receiver) { let config_clone = { // We need to clone the config because we can't hold the lock while we're in the tokio runtime. let server_context = _server_context_mutex.lock().await; @@ -45,7 +65,7 @@ pub(crate) async fn main(_server_context_mutex: Arc { - if o.starts_with("send: ") { - let l = o.split("send: ").collect::>()[1]; + if o.starts_with("parse: ") { + let l = o.split("parse: ").collect::>()[1]; let mut z = y.lock().unwrap(); z.push_str(l); + debug!("JsPluginRuntime is now parsing `{l}` of `{z}`"); let q = from_str::(z.as_str()); match q { Ok(o) => { - println!("{:#?}", o); + debug!("JsPluginRuntime parsed a response: {:?}", o); + rt.spawn(and_now(o, _server_context_mutex.clone())); z.clear(); } _ => {} } } else { if o.replace("\n", "").is_empty() { - // Just wait for the next line lol + // Just wait for the next line lol } else { let mut z = y.lock().unwrap(); z.clear(); - println!("{}", o); + config_clone + .clone() + .tell(format!("[JsPluginRuntime]: {}", o)); } } } @@ -84,20 +108,125 @@ pub(crate) async fn main(_server_context_mutex: Arc { - match r.command.as_str() { - "close" => { - proc.send("close").unwrap() - } - _ => {} - } + Some(o) => { + let mut s = String::from("parse: "); + s.push_str(serde_json::to_string(&o).unwrap().as_str()); + debug!("Sending to JsPluginRuntime: `{}`", s); + proc.send(s.as_str()).unwrap(); } _ => {} } - } } -fn contact_eps() { - todo!() -} \ No newline at end of file +async fn and_now(res: EPSResponse, _server_context_mutex: Arc>) { + let mut server_context = _server_context_mutex.lock().await; + server_context + .external_plugin_server + .response_queue + .push(Some(res)); + debug!("Added response to external plugin server queue."); + // panic!("The function runs! Finally! It runs!"); +} + +pub(crate) async fn contact_eps( + _server_context_mutex: Data>>, + req: EPSRequestBody, +) -> EPSResponse { + let random_id = { + let mut d: EPSCommunicationsID; + loop { + d = rand::random::(); + // Verify that this number is not already in the vector of unreturned responses. + let mut server_context = _server_context_mutex.lock().await; + if !server_context + .external_plugin_server + .response_queue + .iter() + .any(|o| match o { + Some(a) => a.id == d, + None => false, + }) + { + // It's unique! Now add it to the vector to claim it. + server_context.external_plugin_server.unreturned_ids.push(d); + break + } else { + continue; + }; + } + d + }; + + let eps_r = { + let server_context = _server_context_mutex.lock().await; + server_context.external_plugin_server.sender.clone() + }; + match eps_r + .send(EPSRequest { + id: random_id, + body: req, + }) + .await + { + Ok(_) => { + debug!("Sent request to external plugin server."); + } + _ => { + panic!("Failed to send request to external plugin server."); + } + }; + // This function sends a request over mpsc to the externalpluginservers::main function, then periodically locks the server mutex and checks if a corresponding response (matched by `id`) is added, if not, it will try again. + // After sending, check for received responses. + let mut wait = tokio::time::interval(tokio::time::Duration::from_micros(60)); + loop { + wait.tick().await; + { + // Lock the server context mutex and check if the response is in the queue. + let mut server_context = _server_context_mutex.lock().await; + // Remove every none value from server_context.external_plugin_server.response_queue + server_context + .external_plugin_server + .response_queue + .retain(|o| match o { + Some(_) => true, + None => false, + }); + + let left_threads = server_context.external_plugin_server.unreturned_ids.len(); + for o in server_context + .external_plugin_server + .response_queue + .iter_mut() + { + if let Some(a) = o { + debug!("[EPSQuechecker]: Checking response from external plugin server queue: {:?}", a); + if a.id == random_id { + // Match! Return the response and remove it from the vector. + drop(wait); + // Remove it from the unreturned vec + let p = o.take().unwrap(); + drop(server_context); + { + let mut server_context = _server_context_mutex.lock().await; + server_context.external_plugin_server.unreturned_ids.retain( + |a| a != &random_id + ); + return p; + } + } else { + debug!( + "[EPSQuechecker]: No match. Continuing.\n\n\n\r{} <-- What we expected\n\r{} <-- What we got", + random_id, a.id + ); + // No match! Another thread wants this. Keep it in the vector and continue. + // Unless there should be no other thread! Check for this by: + if left_threads <= 1 { + panic!("Incorrect data in the js queue. Might the ID's be altered by js's rounding?") + } + } + }; + } + } + } +} diff --git a/source/Main/src/files.rs b/source/Main/src/files.rs index 374238f..a28b48e 100644 --- a/source/Main/src/files.rs +++ b/source/Main/src/files.rs @@ -3,12 +3,12 @@ * * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. */ -use std::fs; -use std::path::PathBuf; use crate::ServerContext; use log::{debug, trace}; -use std::time::{SystemTime, UNIX_EPOCH}; use normalize_path::NormalizePath; +use std::fs; +use std::path::PathBuf; +use std::time::{SystemTime, UNIX_EPOCH}; pub(super) type CynthiaCache = Vec; #[derive(Debug, Clone)] @@ -99,4 +99,4 @@ pub(crate) fn tempfolder() -> PathBuf { // logger(31, format!("Cache folder: {}", fl.display())); fs::create_dir_all(&fl).unwrap(); fl -} \ No newline at end of file +} diff --git a/source/Main/src/main.rs b/source/Main/src/main.rs index ed97e4f..541c05e 100644 --- a/source/Main/src/main.rs +++ b/source/Main/src/main.rs @@ -4,12 +4,6 @@ * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. */ -use std::fs::File; -use std::path::PathBuf; -use std::{fs, process}; -use std::sync::Arc; -use std::sync::mpsc::Sender; -use std::time::{SystemTime, UNIX_EPOCH}; use actix_web::web::Data; use actix_web::{App, HttpServer}; use colored::Colorize; @@ -19,6 +13,12 @@ use log::info; use log::LevelFilter; use log::{debug, error}; use simplelog::{ColorChoice, CombinedLogger, TermLogger, TerminalMode, WriteLogger}; +use std::fs::File; +use std::option::Option; +use std::path::PathBuf; +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; +use std::{fs, process}; use tokio::sync::{Mutex, MutexGuard}; use crate::config::{CynthiaConf, SceneCollectionTrait}; @@ -27,12 +27,12 @@ use crate::files::CynthiaCache; use crate::tell::horizline; mod config; +mod externalpluginservers; mod files; mod publications; mod renders; mod requestresponse; mod tell; -mod externalpluginservers; // mod jsrun; struct LogSets { @@ -48,7 +48,18 @@ struct ServerContext { cache: CynthiaCache, request_count: u64, start_time: u128, - external_plugin_server: tokio::sync::mpsc::Sender, + external_plugin_server: EPSCommunicationMemory +} +type EPSCommunicationsID = u32; + +#[derive(Debug)] +struct EPSCommunicationMemory { + /// The sender to the (NodeJS) external plugin server not to be used directly. + pub(crate) sender: tokio::sync::mpsc::Sender, + /// The responses from the external plugin servers + pub(crate) response_queue: Vec>, + /// The IDs that have been sent to the external plugin servers but have not been returned yet. + pub(crate) unreturned_ids: Vec, } #[tokio::main] @@ -243,15 +254,18 @@ async fn start() { .unwrap(); use crate::config::CynthiaConfig; - let (eps_s, eps_r) = tokio::sync::mpsc::channel::(100); - + let (to_eps_s, to_eps_r) = tokio::sync::mpsc::channel::(100); // Initialise context let server_context: ServerContext = ServerContext { config: config.hard_clone(), cache: vec![], request_count: 0, start_time: 0, - external_plugin_server: eps_s, + external_plugin_server: EPSCommunicationMemory { + sender: to_eps_s, + response_queue: vec![], + unreturned_ids: vec![], + }, }; let _ = &server_context.tell(format!( "Logging to {}", @@ -262,29 +276,47 @@ async fn start() { .to_string_lossy() .replace("\\\\?\\", "") )); + let _ = fs::remove_dir_all("./.cynthiaTemp"); + match fs::create_dir_all("./.cynthiaTemp") { + Ok(_) => {} + Err(e) => { + error!( + "Could not create the Cynthia temp folder! Error: {}", + e.to_string().bright_red() + ); + process::exit(1); + } + } let server_context_arc_mutex: Arc> = Arc::new(Mutex::new(server_context)); - let server_context_data: Data>> = Data::new(server_context_arc_mutex.clone()); + let server_context_data: Data>> = + Data::new(server_context_arc_mutex.clone()); use requestresponse::serve; - let main_server = - match HttpServer::new(move || { - App::new().service(serve).app_data(server_context_data.clone()) - }) - .bind(("localhost", config.port)) - { - Ok(o) => { - println!("Running on http://localhost:{}", config.port); - o - } - Err(s) => { - error!( - "Could not bind to port {}, error message: {}", - config.port, s - ); - process::exit(1); - } + let main_server = match HttpServer::new(move || { + App::new() + .service(serve) + .app_data(server_context_data.clone()) + }) + .bind(("localhost", config.port)) + { + Ok(o) => { + println!("Running on http://localhost:{}", config.port); + o } - .run(); - let _ = join!(main_server, close(server_context_arc_mutex.clone()), start_timer(server_context_arc_mutex.clone()), externalpluginservers::main(server_context_arc_mutex.clone(), eps_r)); + Err(s) => { + error!( + "Could not bind to port {}, error message: {}", + config.port, s + ); + process::exit(1); + } + } + .run(); + let _ = join!( + main_server, + close(server_context_arc_mutex.clone()), + start_timer(server_context_arc_mutex.clone()), + externalpluginservers::main(server_context_arc_mutex.clone(), to_eps_r) + ); } async fn start_timer(server_context_mutex: Arc>) { let mut server_context: MutexGuard = server_context_mutex.lock().await; @@ -293,16 +325,17 @@ async fn start_timer(server_context_mutex: Arc>) { .unwrap() .as_millis(); } -async fn close( - server_context_mutex: Arc> -) { +async fn close(server_context_mutex: Arc>) { let _ = tokio::signal::ctrl_c().await; let server_context: MutexGuard = server_context_mutex.lock().await; // Basically now that we block the main thread, we have all the time lol - server_context.external_plugin_server.send(EPSRequest { - id: 0, - command: "close".to_string(), - }).await.unwrap(); + // let _ = server_context + // .external_plugin_server + // .request_channel_sender + // .send(EPSRequest { + // id: 0, + // command: "close".to_string(), + // }); let total_run_time = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() @@ -310,11 +343,23 @@ async fn close( - server_context.start_time; let total_run_time_locale = chrono::Duration::milliseconds(total_run_time as i64); let run_time_hours = total_run_time_locale.num_hours(); - let run_time_minutes = total_run_time_locale.num_minutes() - (total_run_time_locale.num_hours() * 60); - let run_time_seconds = total_run_time_locale.num_seconds() - (total_run_time_locale.num_minutes() * 60); - let run_time_string = format!("{}h {}m {}s", run_time_hours, run_time_minutes, run_time_seconds); - let s = if server_context.request_count == 1 { "" } else { "s" }; - server_context.tell(format!("Closing:\n\n\n\nBye! I served {} request{s} in this run of {}!\n", server_context.request_count, run_time_string)); + let run_time_minutes = + total_run_time_locale.num_minutes() - (total_run_time_locale.num_hours() * 60); + let run_time_seconds = + total_run_time_locale.num_seconds() - (total_run_time_locale.num_minutes() * 60); + let run_time_string = format!( + "{}h {}m {}s", + run_time_hours, run_time_minutes, run_time_seconds + ); + let s = if server_context.request_count == 1 { + "" + } else { + "s" + }; + server_context.tell(format!( + "Closing:\n\n\n\nBye! I served {} request{s} in this run of {}!\n", + server_context.request_count, run_time_string + )); println!("{}", horizline().bright_purple()); process::exit(0); -} \ No newline at end of file +} diff --git a/source/Main/src/requestresponse.rs b/source/Main/src/requestresponse.rs index 1ac12dc..c592e95 100644 --- a/source/Main/src/requestresponse.rs +++ b/source/Main/src/requestresponse.rs @@ -3,20 +3,28 @@ * * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. */ -use std::sync::Arc; use crate::renders::render_from_pgid; use crate::{renders, ServerContext}; use actix_web::web::Data; use actix_web::{get, HttpRequest, HttpResponse, Responder}; use colored::Colorize; use log::warn; +use std::sync::Arc; use tokio::sync::{Mutex, MutexGuard}; +use crate::externalpluginservers::{contact_eps, EPSRequestBody}; + #[get("/{a:.*}")] #[doc = r"Serves pages included in CynthiaConfig, or a default page if not found."] pub(crate) async fn serve( server_context_mutex: Data>>, req: HttpRequest, ) -> impl Responder { + { + let testje = EPSRequestBody::Test { + test: String::from("Hello, World!"), + }; + println!( "{:?}", contact_eps(server_context_mutex.clone(), testje).await); + } let mut server_context: MutexGuard = server_context_mutex.lock().await; server_context.request_count += 1; let page_id = req.match_info().get("a").unwrap_or("root"); diff --git a/source/Main/src/tell.rs b/source/Main/src/tell.rs index cbebdc8..922dc8b 100755 --- a/source/Main/src/tell.rs +++ b/source/Main/src/tell.rs @@ -13,7 +13,7 @@ use colored::Colorize; use log::info; use time::{format_description, OffsetDateTime}; -use crate::config::Logging; +use crate::config::{CynthiaConfClone, Logging}; use crate::ServerContext; const DATE_FORMAT_STR: &str = "[hour]:[minute]:[second]"; @@ -41,6 +41,29 @@ impl ServerContext { format!("{} {} {}", times, "[LOG] ".magenta(), msg) } } +/// For when context is unavailable to be locked, confclone should be able to tell too. +impl CynthiaConfClone { + pub(crate) fn tell(&self, rmsg: impl AsRef) { + let msg = rmsg.as_ref(); + match &self.logs.clone() { + None => { + println!("{}", self.format_tell(msg)); + info!("{}", msg); + } + Some(l) => { + l.clone().to_owned().tell(rmsg); + } + } + } + + pub(crate) fn format_tell(&self, rmsg: impl AsRef) -> String { + let msg = rmsg.as_ref(); + let dt1: OffsetDateTime = SystemTime::now().into(); + let dt_fmt = format_description::parse(DATE_FORMAT_STR).unwrap(); + let times = dt1.format(&dt_fmt).unwrap(); + format!("{} {} {}", times, "[LOG] ".magenta(), msg) + } +} impl Logging { fn tell(self, rmsg: impl AsRef) { let msg = rmsg.as_ref(); diff --git a/source/Plugin-runners/node-plugin-api/main.ts b/source/Plugin-runners/node-plugin-api/main.ts new file mode 100644 index 0000000..c305710 --- /dev/null +++ b/source/Plugin-runners/node-plugin-api/main.ts @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024, MLC 'Strawmelonjuice' Bloeiman + * + * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. + */ +export interface Request { + id: number + body: TestRequestBody | unknown; +} +export interface GenericRequest { + id: number + body: { + for: string; + }; +} + +export interface TestRequest { + id: number + body: TestRequestBody; +} +export interface TestRequestBody { + for: "Test"; + test: string; +} + +let test: Request = { + id: 0, + "body": { + for: "Tests", + test: "Test" + } +} + +export interface EmptyOKResponse { + id: number; + body: { + as: "NoneOk"; + }; +} +export interface OkStringResponseType { + id: number; + body: { + as: "OkString"; + value: string; + }; +} + +export class OkStringResponse implements OkStringResponseType { + body: { as: "OkString"; value: string }; + id: number; + constructor(id: number, value: string) { + this.id = id; + this.body = { + as: "OkString", + value: value + } + } +} +export interface OkJSONResponse { + id: number; + body: { + as: "OkJSON"; + value: unknown; + }; +} +export interface ErrorResponse { + id: number; + body: { + as: "Error"; + message?: string; + }; +} +export const Cynthia = { + send: (res: EmptyOKResponse | OkStringResponseType | OkJSONResponse | ErrorResponse) => { + console.log(`parse: ${JSON.stringify(res)}`); + }, +}; +export namespace Incoming { + export interface WebRequest { + method: string; + url: string; + headers: Record; + body: string; + } +} \ No newline at end of file diff --git a/source/Plugin-runners/node-plugin-api/package.json b/source/Plugin-runners/node-plugin-api/package.json index 46e3552..b841128 100644 --- a/source/Plugin-runners/node-plugin-api/package.json +++ b/source/Plugin-runners/node-plugin-api/package.json @@ -1,11 +1,14 @@ { "name": "cynthia-plugin-api", "version": "1.0.0", + "module": "main.js", "description": "Contains some classes and functions to help you create CynthiaWeb plugins.", - "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "MLC Bloeiman", - "license": "ISC" -} + "license": "ISC", + "devDependencies": { + "@types/node": "latest", + } +} \ No newline at end of file diff --git a/source/Plugin-runners/node-plugin-runner/src/main.ts b/source/Plugin-runners/node-plugin-runner/src/main.ts index 5dcec1b..5cc6df2 100644 --- a/source/Plugin-runners/node-plugin-runner/src/main.ts +++ b/source/Plugin-runners/node-plugin-runner/src/main.ts @@ -4,27 +4,48 @@ * Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3, see the LICENSE file for more information. */ -const cynthia = { - -} +import * as CynthiaPluginAPI from "cynthia-plugin-api/main"; +import {Cynthia} from "cynthia-plugin-api/main"; const cynthiabase = { - modifyOutputHTML: [ - (htmlin: string, cynthia) => { - // Make no changes. Return unchanged. - return htmlin; - }, - ], - modifyBodyHTML: [ - (htmlin: string) => { - // Make no changes. Return unchanged. - return htmlin; - }, - ], - requestOptions: [ - () => { - void expressapp; - }, - ], - LogReader: [(type: string, msg: string) => { }], -}; \ No newline at end of file + modifyOutputHTML: [ + (htmlin: string, Cynthia: typeof CynthiaPluginAPI.Cynthia) => { + // Make no changes. Return unchanged. + return htmlin; + }, + ], + modifyBodyHTML: [ + (htmlin: string, Cynthia: typeof CynthiaPluginAPI.Cynthia) => { + // Make no changes. Return unchanged. + return htmlin; + }, + ], + requestOptions: [ + (WebRequest: CynthiaPluginAPI.Incoming.WebRequest, Cynthia: typeof CynthiaPluginAPI.Cynthia) => { + // Make no changes. Return unchanged. + }, + ], +}; +process.stdin.resume(); +process.stdin.on("data", handle); + +function handle(buffer: Buffer) { + if (buffer.toString().startsWith("parse: ")) { + const str = buffer.toString().replace("parse: ", ""); + let request: CynthiaPluginAPI.GenericRequest = JSON.parse(str); + switch (request.body.for) { + case "Exit": { + console.error("Exiting..."); + return (process.exit(0)); + } + case "Test": { + let request: CynthiaPluginAPI.TestRequest = JSON.parse(str); + // {"id":0,"body":{"as":"OkString","value":"Yes."}} + let response = new CynthiaPluginAPI.OkStringResponse(request.id, `Successfully received test request. Test passed with echo: "${request.body.test}"`); + return Cynthia.send(response); + } + } + } else { + console.log(`Got: ${buffer}`); + } +} diff --git a/tsconfig.json b/tsconfig.json index 636db2f..6260a59 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,5 +18,5 @@ "exclude": [ "./target/generated/js/" ], - "include": ["./source/Plugin-runners/node-plugin-runner/src/", "./source/Plugin-runners/node-plugin-api/src"] + "include": ["./source/Plugin-runners/node-plugin-runner/src/"] }