From e1b6b6b8b58fd3fad09739f3432aaa53dbbd49f9 Mon Sep 17 00:00:00 2001 From: Darkatse <39111369+Darkatse@users.noreply.github.com> Date: Wed, 13 May 2026 23:49:06 +0800 Subject: [PATCH] feat(frontend): sync SillyTavern 1.18 baseline Advance the frontend compatibility baseline from SillyTavern 1.16.0 to 1.18.0 while preserving TauriTavern host contracts. - Add upstream sync planning docs and fastools upsync reporting support - Merge upstream frontend updates across index, lib, extensions, script, styles, locales, templates, and bundled extensions - Preserve Tauri bootstrapping, request interception, extension asset loading, mobile layout, and windowed chat semantics - Add request compression, streaming display, swipe picker, theme generation, updated icons, and compatibility baseline checks - Align frontend and backend SillyTavern compatibility metadata to 1.18.0 - Trim package dependencies to the browser bundle and Tauri toolchain, removing unused Node backend packages - Add contract coverage for the browser ESM graph and compatibility baseline --- fastools/src/upsync.rs | 268 +- package.json | 133 +- pnpm-lock.yaml | 5720 +---------------- pnpm-workspace.yaml | 2 + src-tauri/src/presentation/commands/bridge.rs | 2 +- src/compat-version.js | 2 +- src/css/!USER-CSS-README.md | 7 + src/css/loader.css | 57 + src/css/streaming-display.css | 236 + src/css/toggle-dependent.css | 10 + src/css/welcome.css | 1 + src/global.d.ts | 5 +- src/img/logo.svg | 2 + src/img/minimax.svg | 1 + src/img/workers_ai.svg | 9 + src/index.html | 373 +- src/lib-bundle-core.js | 11 +- src/lib.js | 6 + src/locales/ar-sa.json | 18 +- src/locales/de-de.json | 18 +- src/locales/es-es.json | 18 +- src/locales/fr-fr.json | 26 +- src/locales/is-is.json | 18 +- src/locales/it-it.json | 18 +- src/locales/ja-jp.json | 18 +- src/locales/ko-kr.json | 20 +- src/locales/nl-nl.json | 18 +- src/locales/pt-pt.json | 18 +- src/locales/ru-ru.json | 24 +- src/locales/th-th.json | 18 +- src/locales/uk-ua.json | 18 +- src/locales/vi-vn.json | 18 +- src/script.js | 862 ++- src/scripts/BulkEditOverlay.js | 20 +- src/scripts/a11y.js | 1 + src/scripts/action-loader-slashcommands.js | 370 ++ src/scripts/action-loader.js | 617 ++ src/scripts/bookmarks.js | 75 +- src/scripts/bulk-edit.js | 2 +- src/scripts/cfg-scale.js | 1 - src/scripts/chat-backups.js | 2 +- src/scripts/constants.js | 2 + src/scripts/extensions.js | 810 ++- src/scripts/extensions/attachments/index.js | 4 +- .../extensions/attachments/manage-button.html | 2 +- .../extensions/attachments/manifest.json | 5 +- src/scripts/extensions/gallery/index.js | 26 +- src/scripts/extensions/gallery/manifest.json | 5 +- src/scripts/extensions/token-counter/index.js | 5 +- .../extensions/token-counter/manifest.json | 5 +- src/scripts/extensions/translate/index.js | 4 +- .../extensions/translate/manifest.json | 5 +- src/scripts/f-localStorage.js | 1 - src/scripts/filters.js | 16 +- src/scripts/input-md-formatting.js | 9 +- src/scripts/keyboard.js | 6 + src/scripts/logit-bias.js | 14 +- src/scripts/macros.js | 23 +- src/scripts/macros/definitions/chat-macros.js | 12 + src/scripts/macros/definitions/core-macros.js | 27 +- src/scripts/macros/definitions/env-macros.js | 24 + src/scripts/macros/engine/MacroCstWalker.js | 5 +- src/scripts/macros/engine/MacroEnv.types.js | 2 + src/scripts/macros/engine/MacroEnvBuilder.js | 11 +- src/scripts/reasoning.js | 154 +- src/scripts/request-compression.js | 131 + src/scripts/samplerSelect.js | 7 +- src/scripts/secrets.js | 2 +- src/scripts/showdown-underscore.js | 2 +- src/scripts/sse-stream.js | 52 +- src/scripts/stats.js | 3 +- src/scripts/streaming-display.js | 430 ++ src/scripts/swipe-picker.js | 444 ++ src/scripts/tags.js | 150 +- src/scripts/templates/tabbyDownloader.html | 2 +- .../templates/thirdPartyExtensionWarning.html | 18 + src/scripts/templates/wandMenu.html | 1 + src/scripts/util/SimpleMutex.js | 3 +- src/scripts/util/ThemeGenerator.js | 322 + src/scripts/utils.js | 68 + src/scripts/variables.js | 34 +- src/types.d.ts | 6 - tests/browser-esm-graph-contract.test.mjs | 281 + .../compat-baseline-version-contract.test.mjs | 23 + 84 files changed, 5729 insertions(+), 6490 deletions(-) create mode 100644 pnpm-workspace.yaml create mode 100644 src/css/!USER-CSS-README.md create mode 100644 src/css/streaming-display.css create mode 100644 src/img/logo.svg create mode 100644 src/img/minimax.svg create mode 100644 src/img/workers_ai.svg create mode 100644 src/scripts/action-loader-slashcommands.js create mode 100644 src/scripts/action-loader.js create mode 100644 src/scripts/request-compression.js create mode 100644 src/scripts/streaming-display.js create mode 100644 src/scripts/swipe-picker.js create mode 100644 src/scripts/templates/thirdPartyExtensionWarning.html create mode 100644 src/scripts/util/ThemeGenerator.js create mode 100644 tests/browser-esm-graph-contract.test.mjs create mode 100644 tests/compat-baseline-version-contract.test.mjs diff --git a/fastools/src/upsync.rs b/fastools/src/upsync.rs index 2f801bf3..4f154211 100644 --- a/fastools/src/upsync.rs +++ b/fastools/src/upsync.rs @@ -2,18 +2,18 @@ use anyhow::{anyhow, bail, Context, Result}; use chrono::Local; use regex::Regex; use serde::Serialize; -use std::collections::BTreeSet; +use std::collections::{BTreeMap, BTreeSet}; use std::env; use std::fs; use std::path::{Path, PathBuf}; use walkdir::WalkDir; -const DEFAULT_BASE: &str = "sillytavern-1.15.0/public"; -const DEFAULT_TARGET: &str = "sillytavern-1.16.0/public"; +const DEFAULT_BASE: &str = "sillytavern-1.16.0/public"; +const DEFAULT_TARGET: &str = "sillytavern-1.18.0/public"; const DEFAULT_LOCAL: &str = "src"; const DEFAULT_ROUTE_DIR: &str = "src/tauri/main/routes"; const DEFAULT_COMMAND_REGISTRY: &str = "src-tauri/src/presentation/commands/registry.rs"; -const DEFAULT_OUT: &str = "docs/upstream-sync-1.16-plan/reports"; +const DEFAULT_OUT: &str = "docs/upstream-sync-1.18-plan/reports"; const IGNORED_PREFIXES: &[&str] = &["scripts/extensions/third-party/JS-Slash-Runner/"]; @@ -21,6 +21,7 @@ const REPORT_FILE_CLASSIFICATION: &str = "01-file-classification.json"; const REPORT_INJECTION_CONFLICTS: &str = "02-injection-conflicts.json"; const REPORT_ENDPOINT_GAP: &str = "03-endpoint-gap.json"; const REPORT_COMMAND_GAP: &str = "04-command-gap.json"; +const REPORT_ENDPOINT_TRACE: &str = "05-endpoint-trace.json"; const REPORT_SUMMARY: &str = "summary.md"; const INJECTION_KEYWORDS: &[&str] = &[ @@ -130,6 +131,8 @@ struct FileClassificationData { upstream_changed: Vec, local_changed: Vec, both_changed: Vec, + already_synced: Vec, + both_changed_diverged: Vec, upstream_only_changed: Vec, local_only_changed: Vec, } @@ -151,6 +154,8 @@ struct FileClassificationSummary { upstream_changed: usize, local_changed: usize, both_changed: usize, + already_synced: usize, + both_changed_diverged: usize, upstream_only_changed: usize, local_only_changed: usize, } @@ -163,6 +168,8 @@ struct FileClassificationReport { upstream_changed: Vec, local_changed: Vec, both_changed: Vec, + already_synced: Vec, + both_changed_diverged: Vec, upstream_only_changed: Vec, local_only_changed: Vec, } @@ -208,6 +215,43 @@ struct EndpointGapReport { route_patterns: Vec, } +#[derive(Debug)] +struct EndpointOccurrence { + endpoint: String, + path: String, + line: usize, +} + +#[derive(Serialize)] +struct EndpointTraceSummary { + target_endpoints: usize, + target_occurrences: usize, + new_target_endpoints: usize, + new_unhandled_endpoints: usize, +} + +#[derive(Clone, Serialize)] +struct EndpointCallSite { + path: String, + line: usize, +} + +#[derive(Serialize)] +struct EndpointTraceItem { + endpoint: String, + is_new_in_target: bool, + handled_by_local_route: bool, + route_patterns: Vec, + target_call_sites: Vec, +} + +#[derive(Serialize)] +struct EndpointTraceReport { + generated_at: String, + summary: EndpointTraceSummary, + endpoints: Vec, +} + #[derive(Serialize)] struct CommandGapSummary { invoked_commands: usize, @@ -245,18 +289,24 @@ pub fn run_upsync_analyze_cli(args: &[String]) -> Result<()> { upstream_changed: classification.upstream_changed.len(), local_changed: classification.local_changed.len(), both_changed: classification.both_changed.len(), + already_synced: classification.already_synced.len(), + both_changed_diverged: classification.both_changed_diverged.len(), upstream_only_changed: classification.upstream_only_changed.len(), local_only_changed: classification.local_only_changed.len(), }, upstream_changed: classification.upstream_changed.clone(), local_changed: classification.local_changed.clone(), both_changed: classification.both_changed.clone(), + already_synced: classification.already_synced.clone(), + both_changed_diverged: classification.both_changed_diverged.clone(), upstream_only_changed: classification.upstream_only_changed.clone(), local_only_changed: classification.local_only_changed.clone(), }; - let injection_report = analyze_injection_conflicts(&opts, &classification.both_changed)?; + let injection_report = + analyze_injection_conflicts(&opts, &classification.both_changed_diverged)?; let endpoint_gap_report = analyze_endpoint_gaps(&opts)?; + let endpoint_trace_report = analyze_endpoint_trace(&opts)?; let command_gap_report = analyze_command_gaps(&opts)?; fs::create_dir_all(&opts.out_dir).with_context(|| { @@ -279,11 +329,16 @@ pub fn run_upsync_analyze_cli(args: &[String]) -> Result<()> { &endpoint_gap_report, )?; write_json_report(&opts.out_dir.join(REPORT_COMMAND_GAP), &command_gap_report)?; + write_json_report( + &opts.out_dir.join(REPORT_ENDPOINT_TRACE), + &endpoint_trace_report, + )?; write_summary_markdown( &opts.out_dir.join(REPORT_SUMMARY), &classification_report, &injection_report, &endpoint_gap_report, + &endpoint_trace_report, &command_gap_report, )?; @@ -297,6 +352,7 @@ pub fn run_upsync_analyze_cli(args: &[String]) -> Result<()> { println!(" - {}", REPORT_INJECTION_CONFLICTS); println!(" - {}", REPORT_ENDPOINT_GAP); println!(" - {}", REPORT_COMMAND_GAP); + println!(" - {}", REPORT_ENDPOINT_TRACE); println!(" - {}", REPORT_SUMMARY); Ok(()) } @@ -343,6 +399,16 @@ fn classify_files(opts: &AnalyzeOptions) -> Result { .intersection(&local_changed_set) .cloned() .collect(); + let mut already_synced_set = BTreeSet::new(); + let mut both_changed_diverged_set = BTreeSet::new(); + for rel in &both_changed_set { + if files_differ(&opts.target_dir, &opts.local_dir, rel)? { + both_changed_diverged_set.insert(rel.clone()); + } else { + already_synced_set.insert(rel.clone()); + } + } + let upstream_only_set: BTreeSet = upstream_changed_set .difference(&local_changed_set) .cloned() @@ -356,6 +422,8 @@ fn classify_files(opts: &AnalyzeOptions) -> Result { upstream_changed: upstream_changed_set.into_iter().collect(), local_changed: local_changed_set.into_iter().collect(), both_changed: both_changed_set.into_iter().collect(), + already_synced: already_synced_set.into_iter().collect(), + both_changed_diverged: both_changed_diverged_set.into_iter().collect(), upstream_only_changed: upstream_only_set.into_iter().collect(), local_only_changed: local_only_set.into_iter().collect(), }) @@ -573,6 +641,64 @@ fn analyze_endpoint_gaps(opts: &AnalyzeOptions) -> Result { }) } +fn analyze_endpoint_trace(opts: &AnalyzeOptions) -> Result { + let endpoints_base = extract_static_endpoints(&opts.base_dir)?; + let target_occurrences = extract_endpoint_occurrences(&opts.target_dir)?; + let route_patterns = extract_route_patterns(&opts.route_dir)?; + + let mut call_sites_by_endpoint: BTreeMap> = BTreeMap::new(); + for occurrence in target_occurrences { + call_sites_by_endpoint + .entry(occurrence.endpoint) + .or_default() + .push(EndpointCallSite { + path: occurrence.path, + line: occurrence.line, + }); + } + + let mut new_target_endpoints = 0; + let mut new_unhandled_endpoints = 0; + let mut items = Vec::with_capacity(call_sites_by_endpoint.len()); + + for (endpoint, call_sites) in call_sites_by_endpoint { + let is_new_in_target = !endpoints_base.contains(&endpoint); + let route_matches = matching_route_patterns(&endpoint, &route_patterns); + let handled_by_local_route = !route_matches.is_empty(); + + if is_new_in_target { + new_target_endpoints += 1; + if !handled_by_local_route { + new_unhandled_endpoints += 1; + } + } + + items.push(EndpointTraceItem { + endpoint, + is_new_in_target, + handled_by_local_route, + route_patterns: route_matches, + target_call_sites: call_sites, + }); + } + + let target_occurrences = items + .iter() + .map(|item| item.target_call_sites.len()) + .sum::(); + + Ok(EndpointTraceReport { + generated_at: now_rfc3339(), + summary: EndpointTraceSummary { + target_endpoints: items.len(), + target_occurrences, + new_target_endpoints, + new_unhandled_endpoints, + }, + endpoints: items, + }) +} + fn analyze_command_gaps(opts: &AnalyzeOptions) -> Result { let invoked_commands = extract_safe_invoke_commands(&opts.route_dir, &opts.local_dir)?; let registered_commands = extract_registered_commands(&opts.command_registry)?; @@ -596,9 +722,16 @@ fn analyze_command_gaps(opts: &AnalyzeOptions) -> Result { } fn extract_static_endpoints(root: &Path) -> Result> { + Ok(extract_endpoint_occurrences(root)? + .into_iter() + .map(|occurrence| occurrence.endpoint) + .collect()) +} + +fn extract_endpoint_occurrences(root: &Path) -> Result> { let endpoint_regex = Regex::new(r#"['"](/(?:api|csrf-token|version)[^'"\s]*)['"]"#) .context("Failed to compile endpoint regex")?; - let mut endpoints = BTreeSet::new(); + let mut occurrences = Vec::new(); for entry in WalkDir::new(root) { let entry = entry @@ -612,18 +745,35 @@ fn extract_static_endpoints(root: &Path) -> Result> { if let Some(raw) = captures.get(1) { let endpoint = normalize_endpoint(raw.as_str()); if is_relevant_endpoint(&endpoint) { - endpoints.insert(endpoint); + let path = entry + .path() + .strip_prefix(root) + .with_context(|| { + format!( + "Failed to strip prefix {} from {}", + normalize_path_string(root), + normalize_path_string(entry.path()) + ) + })? + .to_string_lossy() + .replace('\\', "/"); + occurrences.push(EndpointOccurrence { + endpoint, + path, + line: line_number_at(&content, raw.start()), + }); } } } } - Ok(endpoints) + Ok(occurrences) } fn extract_route_patterns(route_dir: &Path) -> Result> { - let route_regex = Regex::new(r#"router\.(?:get|post|all)\(\s*['"]([^'"]+)['"]"#) - .context("Failed to compile route regex")?; + let route_regex = + Regex::new(r#"router\.(?:get|post|put|delete|patch|all)\(\s*['"]([^'"]+)['"]"#) + .context("Failed to compile route regex")?; let mut routes = BTreeSet::new(); for entry in WalkDir::new(route_dir) { @@ -649,14 +799,21 @@ fn extract_route_patterns(route_dir: &Path) -> Result> { } fn extract_safe_invoke_commands(route_dir: &Path, local_dir: &Path) -> Result> { - let invoke_regex = Regex::new(r#"safeInvoke\(\s*['"]([^'"]+)['"]"#) + let invoke_regex = Regex::new(r#"(?:safeInvoke|invoke)\(\s*['"]([^'"]+)['"]"#) .context("Failed to compile invoke regex")?; let mut commands = BTreeSet::new(); - let mut scan_roots = vec![route_dir.to_path_buf()]; - let context_path = local_dir.join("tauri/main/context.js"); - if context_path.exists() { - scan_roots.push(context_path); + let mut scan_roots = BTreeSet::new(); + scan_roots.insert(route_dir.to_path_buf()); + + let tauri_main_dir = local_dir.join("tauri/main"); + if tauri_main_dir.exists() { + scan_roots.insert(tauri_main_dir); + } + + let bridge_path = local_dir.join("tauri-bridge.js"); + if bridge_path.exists() { + scan_roots.insert(bridge_path); } for root in scan_roots { @@ -664,7 +821,10 @@ fn extract_safe_invoke_commands(route_dir: &Path, local_dir: &Path) -> Result Result Result bool { + !command.contains(':') +} + fn is_endpoint_handled(endpoint: &str, routes: &BTreeSet) -> bool { + !matching_route_patterns(endpoint, routes).is_empty() +} + +fn matching_route_patterns(endpoint: &str, routes: &BTreeSet) -> Vec { + let mut matches = Vec::new(); for pattern in routes { if pattern.ends_with('*') { let prefix = pattern.trim_end_matches('*'); if endpoint.starts_with(prefix) { - return true; + matches.push(pattern.clone()); } } else if pattern == endpoint { - return true; + matches.push(pattern.clone()); } } - false + matches } fn write_json_report(path: &Path, value: &T) -> Result<()> { @@ -734,6 +906,7 @@ fn write_summary_markdown( classification: &FileClassificationReport, injection: &InjectionConflictReport, endpoints: &EndpointGapReport, + endpoint_trace: &EndpointTraceReport, commands: &CommandGapReport, ) -> Result<()> { let mut text = String::new(); @@ -780,6 +953,14 @@ fn write_summary_markdown( "- Both changed: **{}**\n", classification.summary.both_changed )); + text.push_str(&format!( + "- Already synced with target: **{}**\n", + classification.summary.already_synced + )); + text.push_str(&format!( + "- Both changed but diverged: **{}**\n", + classification.summary.both_changed_diverged + )); text.push_str(&format!( "- Upstream-only changed: **{}**\n", classification.summary.upstream_only_changed @@ -789,8 +970,8 @@ fn write_summary_markdown( classification.summary.local_only_changed )); - text.push_str("### Both Changed (top 40)\n\n"); - for path in classification.both_changed.iter().take(40) { + text.push_str("### Both Changed but Diverged (top 40)\n\n"); + for path in classification.both_changed_diverged.iter().take(40) { text.push_str(&format!("- `{}`\n", path)); } text.push('\n'); @@ -857,6 +1038,42 @@ fn write_summary_markdown( } text.push('\n'); + text.push_str("## Endpoint Trace\n\n"); + text.push_str(&format!( + "- Target endpoint call sites: **{}**\n", + endpoint_trace.summary.target_occurrences + )); + text.push_str(&format!( + "- Target endpoints: **{}**\n", + endpoint_trace.summary.target_endpoints + )); + text.push_str(&format!( + "- New target endpoints: **{}**\n", + endpoint_trace.summary.new_target_endpoints + )); + text.push_str(&format!( + "- New unhandled endpoints: **{}**\n\n", + endpoint_trace.summary.new_unhandled_endpoints + )); + + text.push_str("### New Unhandled Endpoint Call Sites (top 40)\n\n"); + for item in endpoint_trace + .endpoints + .iter() + .filter(|item| item.is_new_in_target && !item.handled_by_local_route) + .take(40) + { + let call_sites = item + .target_call_sites + .iter() + .take(3) + .map(|site| format!("{}:{}", site.path, site.line)) + .collect::>() + .join(", "); + text.push_str(&format!("- `{}`: {}\n", item.endpoint, call_sites)); + } + text.push('\n'); + text.push_str("## Command Gaps\n\n"); text.push_str(&format!( "- Invoked commands: **{}**\n", @@ -903,6 +1120,13 @@ fn contains_keyword(text: Option<&str>, keyword: &str) -> bool { .unwrap_or(false) } +fn line_number_at(content: &str, byte_index: usize) -> usize { + let Some(prefix) = content.get(..byte_index) else { + return content.lines().count().max(1); + }; + prefix.bytes().filter(|byte| *byte == b'\n').count() + 1 +} + fn is_endpoint_source_file(path: &Path) -> bool { match path.extension().and_then(|ext| ext.to_str()) { Some(ext) => { diff --git a/package.json b/package.json index e0fd2152..381f6091 100644 --- a/package.json +++ b/package.json @@ -33,152 +33,43 @@ }, "devDependencies": { "@tauri-apps/cli": "^2.10.0", - "@types/archiver": "^6.0.3", - "@types/bytes": "^3.1.5", - "@types/command-exists": "^1.2.3", - "@types/compression": "^1.7.5", - "@types/cookie-parser": "^1.4.8", - "@types/cookie-session": "^2.0.49", - "@types/cors": "^2.8.17", - "@types/deno": "^2.2.0", - "@types/express": "^4.17.21", "@types/jquery": "^3.5.33", "@types/jquery-cropper": "^1.0.4", "@types/jquery.transit": "^0.9.33", "@types/jqueryui": "^1.12.24", - "@types/lodash": "^4.17.20", - "@types/mime-types": "^2.1.4", - "@types/multer": "^1.4.12", + "@types/lodash": "^4.17.24", "@types/node": "^18.19.84", - "@types/node-persist": "^3.1.8", - "@types/png-chunk-text": "^1.0.3", - "@types/png-chunks-extract": "^1.0.2", - "@types/response-time": "^2.3.8", "@types/select2": "^4.0.63", "@types/toastr": "^2.1.43", - "@types/write-file-atomic": "^4.0.3", - "@types/yargs": "^17.0.33", - "@types/yauzl": "^2.10.3", - "assert": "^2.1.0", - "buffer": "^6.0.3", - "crypto-browserify": "^3.12.0", - "eslint": "^8.57.1", - "eslint-plugin-jsdoc": "^48.10.0", - "os-browserify": "^0.3.0", - "path-browserify": "^1.0.1", - "stream-browserify": "^3.0.0", - "typescript": "^5.5.4", - "util": "^0.12.5", + "es-module-lexer": "^2.0.0", + "typescript": "^5.9.3", + "webpack": "^5.105.4", "webpack-cli": "^5.1.4" }, "dependencies": { "@adobe/css-tools": "^4.4.4", - "@agnai/sentencepiece-js": "^1.1.1", - "@agnai/web-tokenizers": "^0.1.3", "@iconfu/svg-inject": "^1.2.3", - "@jimp/core": "^1.6.0", - "@jimp/js-bmp": "^1.6.0", - "@jimp/js-gif": "^1.6.0", - "@jimp/js-tiff": "^1.6.0", - "@jimp/plugin-circle": "^1.6.0", - "@jimp/plugin-color": "^1.6.0", - "@jimp/plugin-contain": "^1.6.0", - "@jimp/plugin-cover": "^1.6.0", - "@jimp/plugin-crop": "^1.6.0", - "@jimp/plugin-displace": "^1.6.0", - "@jimp/plugin-fisheye": "^1.6.0", - "@jimp/plugin-flip": "^1.6.0", - "@jimp/plugin-mask": "^1.6.0", - "@jimp/plugin-quantize": "^1.6.0", - "@jimp/plugin-rotate": "^1.6.0", - "@jimp/plugin-threshold": "^1.6.0", - "@jimp/wasm-avif": "^1.6.0", - "@jimp/wasm-jpeg": "^1.6.0", - "@jimp/wasm-png": "^1.6.0", - "@jimp/wasm-webp": "^1.6.0", "@mozilla/readability": "^0.6.0", "@popperjs/core": "^2.11.8", - "@tauri-apps/api": "^2.10.1", - "@tauri-apps/plugin-fs": "^2.5.0", - "@tauri-apps/plugin-opener": "~2.5.3", - "@zeldafan0225/ai_horde": "^5.2.0", - "archiver": "^7.0.1", - "bing-translate-api": "^4.0.2", - "body-parser": "^1.20.2", "bowser": "^2.12.1", - "bytes": "^3.1.2", - "chalk": "^5.4.1", - "chevrotain": "^11.0.3", - "command-exists": "^1.2.9", - "compression": "^1.8.0", - "cookie-parser": "^1.4.6", - "cookie-session": "^2.1.0", - "cors": "^2.8.5", - "crc": "^4.3.2", - "csrf-sync": "^4.0.3", + "chevrotain": "^11.2.0", "diff-match-patch": "^1.0.5", - "dompurify": "^3.2.6", + "dompurify": "^3.4.2", "droll": "^0.2.1", - "es-module-lexer": "^2.0.0", - "express": "^4.21.0", - "form-data": "^4.0.2", + "fflate": "^0.8.2", "fuse.js": "^7.1.0", - "google-translate-api-browser": "^3.0.1", - "google-translate-api-x": "^10.7.2", - "handlebars": "^4.7.8", - "helmet": "^7.2.0", + "handlebars": "^4.7.9", "highlight.js": "^11.11.1", - "html-entities": "^2.6.0", - "iconv-lite": "^0.6.3", - "ip-matching": "^2.1.2", - "ip-regex": "^5.0.0", - "ipaddr.js": "^2.2.0", - "is-docker": "^3.0.0", + "js-sha256": "^0.11.1", "localforage": "^1.10.0", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "mime-types": "^2.1.35", + "lodash": "^4.18.1", "moment": "^2.30.1", "morphdom": "^2.7.7", - "multer": "^1.4.5-lts.1", - "node-fetch": "^3.3.2", - "node-persist": "^4.0.4", - "open": "^8.4.2", - "png-chunk-text": "^1.0.0", - "png-chunks-extract": "^1.0.0", - "proxy-agent": "^6.5.0", - "rate-limiter-flexible": "^5.0.5", - "response-time": "^2.3.3", - "sanitize-filename": "^1.6.3", "seedrandom": "^3.0.5", "showdown": "^2.1.0", - "sillytavern-transformers": "2.14.6", - "simple-git": "^3.27.0", - "slidetoggle": "^4.0.0", - "tiktoken": "^1.0.22", - "url-join": "^5.0.0", - "vectra": "^0.2.2", - "vue": "^3.5.33", - "wavefile": "^11.0.0", - "webpack": "^5.98.0", - "write-file-atomic": "^5.0.1", - "ws": "^8.18.1", - "yaml": "^2.8.1", - "yargs": "^17.7.1", - "yauzl": "^2.10.0" + "vue": "^3.5.33" }, "engines": { - "node": ">= 18" - }, - "overrides": { - "vectra": { - "openai": "^4.17.0" - }, - "axios": { - "follow-redirects": "^1.15.4" - }, - "node-fetch": { - "whatwg-url": "^14.0.0" - } + "node": ">= 20" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 204f073e..3284f0ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,316 +11,70 @@ importers: '@adobe/css-tools': specifier: ^4.4.4 version: 4.4.4 - '@agnai/sentencepiece-js': - specifier: ^1.1.1 - version: 1.1.1 - '@agnai/web-tokenizers': - specifier: ^0.1.3 - version: 0.1.3 '@iconfu/svg-inject': specifier: ^1.2.3 version: 1.2.3 - '@jimp/core': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/js-bmp': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/js-gif': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/js-tiff': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/plugin-circle': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/plugin-color': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/plugin-contain': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/plugin-cover': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/plugin-crop': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/plugin-displace': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/plugin-fisheye': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/plugin-flip': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/plugin-mask': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/plugin-quantize': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/plugin-rotate': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/plugin-threshold': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/wasm-avif': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/wasm-jpeg': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/wasm-png': - specifier: ^1.6.0 - version: 1.6.0 - '@jimp/wasm-webp': - specifier: ^1.6.0 - version: 1.6.0 '@mozilla/readability': specifier: ^0.6.0 version: 0.6.0 '@popperjs/core': specifier: ^2.11.8 version: 2.11.8 - '@tauri-apps/api': - specifier: ^2.10.1 - version: 2.10.1 - '@tauri-apps/plugin-fs': - specifier: ^2.5.0 - version: 2.5.0 - '@tauri-apps/plugin-opener': - specifier: ~2.5.3 - version: 2.5.3 - '@zeldafan0225/ai_horde': - specifier: ^5.2.0 - version: 5.2.0 - archiver: - specifier: ^7.0.1 - version: 7.0.1 - bing-translate-api: - specifier: ^4.0.2 - version: 4.0.2 - body-parser: - specifier: ^1.20.2 - version: 1.20.3 bowser: specifier: ^2.12.1 version: 2.14.1 - bytes: - specifier: ^3.1.2 - version: 3.1.2 - chalk: - specifier: ^5.4.1 - version: 5.4.1 chevrotain: - specifier: ^11.0.3 - version: 11.1.1 - command-exists: - specifier: ^1.2.9 - version: 1.2.9 - compression: - specifier: ^1.8.0 - version: 1.8.0 - cookie-parser: - specifier: ^1.4.6 - version: 1.4.7 - cookie-session: - specifier: ^2.1.0 - version: 2.1.0 - cors: - specifier: ^2.8.5 - version: 2.8.5 - crc: - specifier: ^4.3.2 - version: 4.3.2(buffer@6.0.3) - csrf-sync: - specifier: ^4.0.3 - version: 4.1.0 + specifier: ^11.2.0 + version: 11.2.0 diff-match-patch: specifier: ^1.0.5 version: 1.0.5 dompurify: - specifier: ^3.2.6 - version: 3.3.1 + specifier: ^3.4.2 + version: 3.4.3 droll: specifier: ^0.2.1 version: 0.2.1 - es-module-lexer: - specifier: ^2.0.0 - version: 2.0.0 - express: - specifier: ^4.21.0 - version: 4.21.2 - form-data: - specifier: ^4.0.2 - version: 4.0.2 + fflate: + specifier: ^0.8.2 + version: 0.8.2 fuse.js: specifier: ^7.1.0 version: 7.1.0 - google-translate-api-browser: - specifier: ^3.0.1 - version: 3.0.1 - google-translate-api-x: - specifier: ^10.7.2 - version: 10.7.2 handlebars: - specifier: ^4.7.8 - version: 4.7.8 - helmet: - specifier: ^7.2.0 - version: 7.2.0 + specifier: ^4.7.9 + version: 4.7.9 highlight.js: specifier: ^11.11.1 version: 11.11.1 - html-entities: - specifier: ^2.6.0 - version: 2.6.0 - iconv-lite: - specifier: ^0.6.3 - version: 0.6.3 - ip-matching: - specifier: ^2.1.2 - version: 2.1.2 - ip-regex: - specifier: ^5.0.0 - version: 5.0.0 - ipaddr.js: - specifier: ^2.2.0 - version: 2.2.0 - is-docker: - specifier: ^3.0.0 - version: 3.0.0 + js-sha256: + specifier: ^0.11.1 + version: 0.11.1 localforage: specifier: ^1.10.0 version: 1.10.0 lodash: - specifier: ^4.17.21 - version: 4.17.21 - lodash-es: - specifier: ^4.17.21 - version: 4.17.21 - mime-types: - specifier: ^2.1.35 - version: 2.1.35 + specifier: ^4.18.1 + version: 4.18.1 moment: specifier: ^2.30.1 version: 2.30.1 morphdom: specifier: ^2.7.7 version: 2.7.8 - multer: - specifier: ^1.4.5-lts.1 - version: 1.4.5-lts.2 - node-fetch: - specifier: ^3.3.2 - version: 3.3.2 - node-persist: - specifier: ^4.0.4 - version: 4.0.4 - open: - specifier: ^8.4.2 - version: 8.4.2 - png-chunk-text: - specifier: ^1.0.0 - version: 1.0.0 - png-chunks-extract: - specifier: ^1.0.0 - version: 1.0.0 - proxy-agent: - specifier: ^6.5.0 - version: 6.5.0 - rate-limiter-flexible: - specifier: ^5.0.5 - version: 5.0.5 - response-time: - specifier: ^2.3.3 - version: 2.3.3 - sanitize-filename: - specifier: ^1.6.3 - version: 1.6.3 seedrandom: specifier: ^3.0.5 version: 3.0.5 showdown: specifier: ^2.1.0 version: 2.1.0 - sillytavern-transformers: - specifier: 2.14.6 - version: 2.14.6 - simple-git: - specifier: ^3.27.0 - version: 3.27.0 - slidetoggle: - specifier: ^4.0.0 - version: 4.0.0 - tiktoken: - specifier: ^1.0.22 - version: 1.0.22 - url-join: - specifier: ^5.0.0 - version: 5.0.0 - vectra: - specifier: ^0.2.2 - version: 0.2.2 vue: specifier: ^3.5.33 version: 3.5.33(typescript@5.9.3) - wavefile: - specifier: ^11.0.0 - version: 11.0.0 - webpack: - specifier: ^5.98.0 - version: 5.99.6(webpack-cli@5.1.4) - write-file-atomic: - specifier: ^5.0.1 - version: 5.0.1 - ws: - specifier: ^8.18.1 - version: 8.18.1 - yaml: - specifier: ^2.8.1 - version: 2.8.2 - yargs: - specifier: ^17.7.1 - version: 17.7.2 - yauzl: - specifier: ^2.10.0 - version: 2.10.0 devDependencies: '@tauri-apps/cli': specifier: ^2.10.0 version: 2.10.0 - '@types/archiver': - specifier: ^6.0.3 - version: 6.0.3 - '@types/bytes': - specifier: ^3.1.5 - version: 3.1.5 - '@types/command-exists': - specifier: ^1.2.3 - version: 1.2.3 - '@types/compression': - specifier: ^1.7.5 - version: 1.7.5 - '@types/cookie-parser': - specifier: ^1.4.8 - version: 1.4.8(@types/express@4.17.21) - '@types/cookie-session': - specifier: ^2.0.49 - version: 2.0.49 - '@types/cors': - specifier: ^2.8.17 - version: 2.8.17 - '@types/deno': - specifier: ^2.2.0 - version: 2.2.0 - '@types/express': - specifier: ^4.17.21 - version: 4.17.21 '@types/jquery': specifier: ^3.5.33 version: 3.5.33 @@ -334,89 +88,35 @@ importers: specifier: ^1.12.24 version: 1.12.24 '@types/lodash': - specifier: ^4.17.20 - version: 4.17.23 - '@types/mime-types': - specifier: ^2.1.4 - version: 2.1.4 - '@types/multer': - specifier: ^1.4.12 - version: 1.4.12 + specifier: ^4.17.24 + version: 4.17.24 '@types/node': specifier: ^18.19.84 version: 18.19.86 - '@types/node-persist': - specifier: ^3.1.8 - version: 3.1.8 - '@types/png-chunk-text': - specifier: ^1.0.3 - version: 1.0.3 - '@types/png-chunks-extract': - specifier: ^1.0.2 - version: 1.0.2 - '@types/response-time': - specifier: ^2.3.8 - version: 2.3.8 '@types/select2': specifier: ^4.0.63 version: 4.0.63 '@types/toastr': specifier: ^2.1.43 version: 2.1.43 - '@types/write-file-atomic': - specifier: ^4.0.3 - version: 4.0.3 - '@types/yargs': - specifier: ^17.0.33 - version: 17.0.33 - '@types/yauzl': - specifier: ^2.10.3 - version: 2.10.3 - assert: - specifier: ^2.1.0 - version: 2.1.0 - buffer: - specifier: ^6.0.3 - version: 6.0.3 - crypto-browserify: - specifier: ^3.12.0 - version: 3.12.1 - eslint: - specifier: ^8.57.1 - version: 8.57.1 - eslint-plugin-jsdoc: - specifier: ^48.10.0 - version: 48.11.0(eslint@8.57.1) - os-browserify: - specifier: ^0.3.0 - version: 0.3.0 - path-browserify: - specifier: ^1.0.1 - version: 1.0.1 - stream-browserify: - specifier: ^3.0.0 - version: 3.0.0 + es-module-lexer: + specifier: ^2.0.0 + version: 2.0.0 typescript: - specifier: ^5.5.4 + specifier: ^5.9.3 version: 5.9.3 - util: - specifier: ^0.12.5 - version: 0.12.5 + webpack: + specifier: ^5.105.4 + version: 5.106.2(webpack-cli@5.1.4) webpack-cli: specifier: ^5.1.4 - version: 5.1.4(webpack@5.99.6) + version: 5.1.4(webpack@5.106.2) packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - '@agnai/sentencepiece-js@1.1.1': - resolution: {integrity: sha512-h2+XPrJVLuVLl+2+3iZPWcTw6Fs2NNulnxyh7LoI1hzHHib1wDC6KTmTrDJlLq7/lr5QFYpeMz2rlTFQrS0C0g==} - - '@agnai/web-tokenizers@0.1.3': - resolution: {integrity: sha512-KlmTftToTtmb6aLVdne4NluS+POWputPF5J8v25UN/EQS+K9vahWEIe1NPRSFqBQclObkqHaj7JOnFrmnSm5MA==} - '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} @@ -434,348 +134,28 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@chevrotain/cst-dts-gen@11.1.1': - resolution: {integrity: sha512-fRHyv6/f542qQqiRGalrfJl/evD39mAvbJLCekPazhiextEatq1Jx1K/i9gSd5NNO0ds03ek0Cbo/4uVKmOBcw==} + '@chevrotain/cst-dts-gen@11.2.0': + resolution: {integrity: sha512-ssJFvn/UXhQQeICw3SR/fZPmYVj+JM2mP+Lx7bZ51cOeHaMWOKp3AUMuyM3QR82aFFXTfcAp67P5GpPjGmbZWQ==} - '@chevrotain/gast@11.1.1': - resolution: {integrity: sha512-Ko/5vPEYy1vn5CbCjjvnSO4U7GgxyGm+dfUZZJIWTlQFkXkyym0jFYrWEU10hyCjrA7rQtiHtBr0EaZqvHFZvg==} + '@chevrotain/gast@11.2.0': + resolution: {integrity: sha512-c+KoD6eSI1xjAZZoNUW+V0l13UEn+a4ShmUrjIKs1BeEWCji0Kwhmqn5FSx1K4BhWL7IQKlV7wLR4r8lLArORQ==} - '@chevrotain/regexp-to-ast@11.1.1': - resolution: {integrity: sha512-ctRw1OKSXkOrR8VTvOxrQ5USEc4sNrfwXHa1NuTcR7wre4YbjPcKw+82C2uylg/TEwFRgwLmbhlln4qkmDyteg==} + '@chevrotain/regexp-to-ast@11.2.0': + resolution: {integrity: sha512-lG73pBFqbXODTbXhdZwv0oyUaI+3Irm+uOv5/W79lI3g5hasYaJnVJOm3H2NkhA0Ef4XLBU4Scr7TJDJwgFkAw==} - '@chevrotain/types@11.1.1': - resolution: {integrity: sha512-wb2ToxG8LkgPYnKe9FH8oGn3TMCBdnwiuNC5l5y+CtlaVRbCytU0kbVsk6CGrqTL4ZN4ksJa0TXOYbxpbthtqw==} + '@chevrotain/types@11.2.0': + resolution: {integrity: sha512-vBMSj/lz/LqolbGQEHB0tlpW5BnljHVtp+kzjQfQU+5BtGMTuZCPVgaAjtKvQYXnHb/8i/02Kii00y0tsuwfsw==} - '@chevrotain/utils@11.1.1': - resolution: {integrity: sha512-71eTYMzYXYSFPrbg/ZwftSaSDld7UYlS8OQa3lNnn9jzNtpFbaReRRyghzqS7rI3CDaorqpPJJcXGHK+FE1TVQ==} + '@chevrotain/utils@11.2.0': + resolution: {integrity: sha512-+7whECg4yNWHottjvr2To2BRxL4XJVjIyyv5J4+bJ0iMOVU8j/8n1qPDLZS/90W/BObDR8VNL46lFbzY/Hosmw==} '@discoveryjs/json-ext@0.5.7': resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} - '@es-joy/jsdoccomment@0.46.0': - resolution: {integrity: sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==} - engines: {node: '>=16'} - - '@eslint-community/eslint-utils@4.6.1': - resolution: {integrity: sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@huggingface/jinja@0.1.3': - resolution: {integrity: sha512-9KsiorsdIK8+7VmlamAT7Uh90zxAhC/SeKaKc80v58JhtPYuwaJpmR/ST7XAUxrHAFqHTCoTH5aJnJDwSL6xIQ==} - engines: {node: '>=18'} - - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead - '@iconfu/svg-inject@1.2.3': resolution: {integrity: sha512-3v1MUAJqmJS4jmhHoCkSxt+EdJrjPHlLXrWocCT25kCxnxJto8028Z6CC406EL11KA53SDZgI/QQA5GEJAoiRw==} - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@jimp/bmp@0.22.12': - resolution: {integrity: sha512-aeI64HD0npropd+AR76MCcvvRaa+Qck6loCOS03CkkxGHN5/r336qTM5HPUdHKMDOGzqknuVPA8+kK1t03z12g==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/core@0.22.12': - resolution: {integrity: sha512-l0RR0dOPyzMKfjUW1uebzueFEDtCOj9fN6pyTYWWOM/VS4BciXQ1VVrJs8pO3kycGYZxncRKhCoygbNr8eEZQA==} - - '@jimp/core@1.6.0': - resolution: {integrity: sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w==} - engines: {node: '>=18'} - - '@jimp/custom@0.22.12': - resolution: {integrity: sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==} - - '@jimp/file-ops@1.6.0': - resolution: {integrity: sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ==} - engines: {node: '>=18'} - - '@jimp/gif@0.22.12': - resolution: {integrity: sha512-y6BFTJgch9mbor2H234VSjd9iwAhaNf/t3US5qpYIs0TSbAvM02Fbc28IaDETj9+4YB4676sz4RcN/zwhfu1pg==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/jpeg@0.22.12': - resolution: {integrity: sha512-Rq26XC/uQWaQKyb/5lksCTCxXhtY01NJeBN+dQv5yNYedN0i7iYu+fXEoRsfaJ8xZzjoANH8sns7rVP4GE7d/Q==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/js-bmp@1.6.0': - resolution: {integrity: sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw==} - engines: {node: '>=18'} - - '@jimp/js-gif@1.6.0': - resolution: {integrity: sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g==} - engines: {node: '>=18'} - - '@jimp/js-jpeg@1.6.0': - resolution: {integrity: sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA==} - engines: {node: '>=18'} - - '@jimp/js-png@1.6.0': - resolution: {integrity: sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg==} - engines: {node: '>=18'} - - '@jimp/js-tiff@1.6.0': - resolution: {integrity: sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw==} - engines: {node: '>=18'} - - '@jimp/plugin-blit@0.22.12': - resolution: {integrity: sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-blit@1.6.0': - resolution: {integrity: sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA==} - engines: {node: '>=18'} - - '@jimp/plugin-blur@0.22.12': - resolution: {integrity: sha512-S0vJADTuh1Q9F+cXAwFPlrKWzDj2F9t/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uw==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-circle@0.22.12': - resolution: {integrity: sha512-SWVXx1yiuj5jZtMijqUfvVOJBwOifFn0918ou4ftoHgegc5aHWW5dZbYPjvC9fLpvz7oSlptNl2Sxr1zwofjTg==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-circle@1.6.0': - resolution: {integrity: sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw==} - engines: {node: '>=18'} - - '@jimp/plugin-color@0.22.12': - resolution: {integrity: sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-color@1.6.0': - resolution: {integrity: sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA==} - engines: {node: '>=18'} - - '@jimp/plugin-contain@0.22.12': - resolution: {integrity: sha512-Eo3DmfixJw3N79lWk8q/0SDYbqmKt1xSTJ69yy8XLYQj9svoBbyRpSnHR+n9hOw5pKXytHwUW6nU4u1wegHNoQ==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - '@jimp/plugin-blit': '>=0.3.5' - '@jimp/plugin-resize': '>=0.3.5' - '@jimp/plugin-scale': '>=0.3.5' - - '@jimp/plugin-contain@1.6.0': - resolution: {integrity: sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ==} - engines: {node: '>=18'} - - '@jimp/plugin-cover@0.22.12': - resolution: {integrity: sha512-z0w/1xH/v/knZkpTNx+E8a7fnasQ2wHG5ze6y5oL2dhH1UufNua8gLQXlv8/W56+4nJ1brhSd233HBJCo01BXA==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - '@jimp/plugin-crop': '>=0.3.5' - '@jimp/plugin-resize': '>=0.3.5' - '@jimp/plugin-scale': '>=0.3.5' - - '@jimp/plugin-cover@1.6.0': - resolution: {integrity: sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA==} - engines: {node: '>=18'} - - '@jimp/plugin-crop@0.22.12': - resolution: {integrity: sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-crop@1.6.0': - resolution: {integrity: sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang==} - engines: {node: '>=18'} - - '@jimp/plugin-displace@0.22.12': - resolution: {integrity: sha512-qpRM8JRicxfK6aPPqKZA6+GzBwUIitiHaZw0QrJ64Ygd3+AsTc7BXr+37k2x7QcyCvmKXY4haUrSIsBug4S3CA==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-displace@1.6.0': - resolution: {integrity: sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q==} - engines: {node: '>=18'} - - '@jimp/plugin-dither@0.22.12': - resolution: {integrity: sha512-jYgGdSdSKl1UUEanX8A85v4+QUm+PE8vHFwlamaKk89s+PXQe7eVE3eNeSZX4inCq63EHL7cX580dMqkoC3ZLw==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-fisheye@0.22.12': - resolution: {integrity: sha512-LGuUTsFg+fOp6KBKrmLkX4LfyCy8IIsROwoUvsUPKzutSqMJnsm3JGDW2eOmWIS/jJpPaeaishjlxvczjgII+Q==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-fisheye@1.6.0': - resolution: {integrity: sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA==} - engines: {node: '>=18'} - - '@jimp/plugin-flip@0.22.12': - resolution: {integrity: sha512-m251Rop7GN8W0Yo/rF9LWk6kNclngyjIJs/VXHToGQ6EGveOSTSQaX2Isi9f9lCDLxt+inBIb7nlaLLxnvHX8Q==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - '@jimp/plugin-rotate': '>=0.3.5' - - '@jimp/plugin-flip@1.6.0': - resolution: {integrity: sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg==} - engines: {node: '>=18'} - - '@jimp/plugin-gaussian@0.22.12': - resolution: {integrity: sha512-sBfbzoOmJ6FczfG2PquiK84NtVGeScw97JsCC3rpQv1PHVWyW+uqWFF53+n3c8Y0P2HWlUjflEla2h/vWShvhg==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-hash@1.6.0': - resolution: {integrity: sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q==} - engines: {node: '>=18'} - - '@jimp/plugin-invert@0.22.12': - resolution: {integrity: sha512-N+6rwxdB+7OCR6PYijaA/iizXXodpxOGvT/smd/lxeXsZ/empHmFFFJ/FaXcYh19Tm04dGDaXcNF/dN5nm6+xQ==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-mask@0.22.12': - resolution: {integrity: sha512-4AWZg+DomtpUA099jRV8IEZUfn1wLv6+nem4NRJC7L/82vxzLCgXKTxvNvBcNmJjT9yS1LAAmiJGdWKXG63/NA==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-mask@1.6.0': - resolution: {integrity: sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA==} - engines: {node: '>=18'} - - '@jimp/plugin-normalize@0.22.12': - resolution: {integrity: sha512-0So0rexQivnWgnhacX4cfkM2223YdExnJTTy6d06WbkfZk5alHUx8MM3yEzwoCN0ErO7oyqEWRnEkGC+As1FtA==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-print@0.22.12': - resolution: {integrity: sha512-c7TnhHlxm87DJeSnwr/XOLjJU/whoiKYY7r21SbuJ5nuH+7a78EW1teOaj5gEr2wYEd7QtkFqGlmyGXY/YclyQ==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - '@jimp/plugin-blit': '>=0.3.5' - - '@jimp/plugin-quantize@1.6.0': - resolution: {integrity: sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg==} - engines: {node: '>=18'} - - '@jimp/plugin-resize@0.22.12': - resolution: {integrity: sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/plugin-resize@1.6.0': - resolution: {integrity: sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA==} - engines: {node: '>=18'} - - '@jimp/plugin-rotate@0.22.12': - resolution: {integrity: sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - '@jimp/plugin-blit': '>=0.3.5' - '@jimp/plugin-crop': '>=0.3.5' - '@jimp/plugin-resize': '>=0.3.5' - - '@jimp/plugin-rotate@1.6.0': - resolution: {integrity: sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw==} - engines: {node: '>=18'} - - '@jimp/plugin-scale@0.22.12': - resolution: {integrity: sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - '@jimp/plugin-resize': '>=0.3.5' - - '@jimp/plugin-shadow@0.22.12': - resolution: {integrity: sha512-FX8mTJuCt7/3zXVoeD/qHlm4YH2bVqBuWQHXSuBK054e7wFRnRnbSLPUqAwSeYP3lWqpuQzJtgiiBxV3+WWwTg==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - '@jimp/plugin-blur': '>=0.3.5' - '@jimp/plugin-resize': '>=0.3.5' - - '@jimp/plugin-threshold@0.22.12': - resolution: {integrity: sha512-4x5GrQr1a/9L0paBC/MZZJjjgjxLYrqSmWd+e+QfAEPvmRxdRoQ5uKEuNgXnm9/weHQBTnQBQsOY2iFja+XGAw==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - '@jimp/plugin-color': '>=0.8.0' - '@jimp/plugin-resize': '>=0.8.0' - - '@jimp/plugin-threshold@1.6.0': - resolution: {integrity: sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w==} - engines: {node: '>=18'} - - '@jimp/plugins@0.22.12': - resolution: {integrity: sha512-yBJ8vQrDkBbTgQZLty9k4+KtUQdRjsIDJSPjuI21YdVeqZxYywifHl4/XWILoTZsjTUASQcGoH0TuC0N7xm3ww==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/png@0.22.12': - resolution: {integrity: sha512-Mrp6dr3UTn+aLK8ty/dSKELz+Otdz1v4aAXzV5q53UDD2rbB5joKVJ/ChY310B+eRzNxIovbUF1KVrUsYdE8Hg==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/tiff@0.22.12': - resolution: {integrity: sha512-E1LtMh4RyJsoCAfAkBRVSYyZDTtLq9p9LUiiYP0vPtXyxX4BiYBUYihTLSBlCQg5nF2e4OpQg7SPrLdJ66u7jg==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/types@0.22.12': - resolution: {integrity: sha512-wwKYzRdElE1MBXFREvCto5s699izFHNVvALUv79GXNbsOVqlwlOxlWJ8DuyOGIXoLP4JW/m30YyuTtfUJgMRMA==} - peerDependencies: - '@jimp/custom': '>=0.3.5' - - '@jimp/types@1.6.0': - resolution: {integrity: sha512-7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg==} - engines: {node: '>=18'} - - '@jimp/utils@0.22.12': - resolution: {integrity: sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==} - - '@jimp/utils@1.6.0': - resolution: {integrity: sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA==} - engines: {node: '>=18'} - - '@jimp/wasm-avif@1.6.0': - resolution: {integrity: sha512-OjiqqtD71MTLVQgB/oUOZ8PD+nxLQtl/Lyf/P/hhL56L6iCJbcciA3xO0Y9OJept7+R34ORY4f7RwWwt535DHg==} - engines: {node: '>=18'} - - '@jimp/wasm-jpeg@1.6.0': - resolution: {integrity: sha512-zURjiESa79XXpMHzvvLMD3RC+wzFevS8lcTgyoZq4/y7qE5WrrUTWUBhr1UMFDueQ4gmOUf6EZ8L3/jkS/6nKQ==} - engines: {node: '>=18'} - - '@jimp/wasm-png@1.6.0': - resolution: {integrity: sha512-D1xTVXpErApFH4YiOWZDoF8S8B6I3PgoCe38WsnTxDLfple8KGZMBdNjv3UO7vczsdlg5rATwWMBbNwxK03jNQ==} - engines: {node: '>=18'} - - '@jimp/wasm-webp@1.6.0': - resolution: {integrity: sha512-P0zUpK6n2XIAn8bt0F6rhSn1+FgteBTrL+TBb6Oqw8v5qEDJoNYkd6LlfZYN8YwtRBTBdZ8GFnWsg2Sar+qOkA==} - engines: {node: '>=18'} - '@jridgewell/gen-mapping@0.3.8': resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} @@ -791,104 +171,19 @@ packages: '@jridgewell/source-map@0.3.6': resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@jsquash/avif@1.3.0': - resolution: {integrity: sha512-N6zH27O/AioCPNGxaf33PYnUEQZmAjUz0JwwAf9eMHRdYItn+CxwxlsHSSOkFmZKW+v9uVX6c7ZPQ4RTXArL7A==} - - '@jsquash/jpeg@1.5.0': - resolution: {integrity: sha512-Jam3X9BhbP1f+d58TfYobV/ZpYhCnawBF7YMS0Vt5Gi1v5Rk+xUdqYiZarAn0PwAzy2Zm2pPU/VzXHsLhwT9QQ==} - - '@jsquash/oxipng@2.3.0': - resolution: {integrity: sha512-aQ8wiEp6ztlTMXc+RMt/CG8crU3mEHDU+h+JYkIi6ctMhlh8+Ltj5XwQFfBuyzKYrp8NxaFW80Dp824bqjr+zA==} - - '@jsquash/png@3.0.1': - resolution: {integrity: sha512-Bnvv93Y5LL92cuk2r2gpV+9JKuDo2/w7bOODw1iPxk8VARknky0sS1tSDgMosUdhNb4CdMlcCm3TMzTaqa3zZw==} - - '@jsquash/webp@1.4.0': - resolution: {integrity: sha512-yKJb6Hilq+qV/4C4qTDEalBobNwJO09LeHHtilmWg5mYHFUDwMunfeAap/r3cL5KsHkGOoI0IjY2nKbTaHq9Bw==} - - '@kwsites/file-exists@1.1.1': - resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} - - '@kwsites/promise-deferred@1.1.1': - resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} - '@mozilla/readability@0.6.0': resolution: {integrity: sha512-juG5VWh4qAivzTAeMzvY9xs9HY5rAcr2E4I7tiSSCokRFi7XIZCAu92ZkSTsIj1OPceCifL3cpfteP3pDT9/QQ==} engines: {node: '>=14.0.0'} - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@pkgr/core@0.1.2': - resolution: {integrity: sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - '@protobufjs/aspromise@1.1.2': - resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} - - '@protobufjs/base64@1.1.2': - resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} - - '@protobufjs/codegen@2.0.4': - resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} - - '@protobufjs/eventemitter@1.1.0': - resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} - - '@protobufjs/fetch@1.1.0': - resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} - - '@protobufjs/float@1.0.2': - resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} - - '@protobufjs/inquire@1.1.0': - resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} - - '@protobufjs/path@1.1.2': - resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} - - '@protobufjs/pool@1.1.0': - resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} - - '@protobufjs/utf8@1.1.0': - resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} - - '@sindresorhus/is@4.6.0': - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} - - '@szmarczak/http-timer@4.0.6': - resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} - engines: {node: '>=10'} - - '@tauri-apps/api@2.10.1': - resolution: {integrity: sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==} - '@tauri-apps/cli-darwin-arm64@2.10.0': resolution: {integrity: sha512-avqHD4HRjrMamE/7R/kzJPcAJnZs0IIS+1nkDP5b+TNBn3py7N2aIo9LIpy+VQq0AkN8G5dDpZtOOBkmWt/zjA==} engines: {node: '>= 10'} @@ -965,76 +260,14 @@ packages: engines: {node: '>= 10'} hasBin: true - '@tauri-apps/plugin-fs@2.5.0': - resolution: {integrity: sha512-c83kbz61AK+rKjhS+je9+stIO27nXj7p9cqeg36TwkIUtxpCFTttlHHtqon6h6FN54cXjyAjlMPOJcW3mwE5XQ==} - - '@tauri-apps/plugin-opener@2.5.3': - resolution: {integrity: sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ==} - - '@thunder04/supermap@3.0.5': - resolution: {integrity: sha512-dVlKfY/+Kiy3Vyy7zUj/X2ZB+6e+2QWsEqMOVAQc15FYNV1lmw4sHn3YE4VBsfmm0Iu/0MABUla8WZMGIdMYwg==} - - '@tokenizer/token@0.3.0': - resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - - '@tootallnate/quickjs-emscripten@0.23.0': - resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} - - '@types/archiver@6.0.3': - resolution: {integrity: sha512-a6wUll6k3zX6qs5KlxIggs1P1JcYJaTCx2gnlr+f0S1yd2DoaEwoIK10HmBaLnZwWneBz+JBm0dwcZu0zECBcQ==} - - '@types/body-parser@1.19.5': - resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} - - '@types/bytes@3.1.5': - resolution: {integrity: sha512-VgZkrJckypj85YxEsEavcMmmSOIzkUHqWmM4CCyia5dc54YwsXzJ5uT4fYxBQNEXx+oF1krlhgCbvfubXqZYsQ==} - - '@types/cacheable-request@6.0.3': - resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} - - '@types/command-exists@1.2.3': - resolution: {integrity: sha512-PpbaE2XWLaWYboXD6k70TcXO/OdOyyRFq5TVpmlUELNxdkkmXU9fkImNosmXU1DtsNrqdUgWd/nJQYXgwmtdXQ==} - - '@types/compression@1.7.5': - resolution: {integrity: sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==} - - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - - '@types/cookie-parser@1.4.8': - resolution: {integrity: sha512-l37JqFrOJ9yQfRQkljb41l0xVphc7kg5JTjjr+pLRZ0IyZ49V4BQ8vbF4Ut2C2e+WH4al3xD3ZwYwIUfnbT4NQ==} - peerDependencies: - '@types/express': '*' - - '@types/cookie-session@2.0.49': - resolution: {integrity: sha512-4E/bBjlqLhU5l4iGPR+NkVJH593hpNsT4dC3DJDr+ODm6Qpe13kZQVkezRIb+TYDXaBMemS3yLQ+0leba3jlkQ==} - - '@types/cors@2.8.17': - resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} - - '@types/deno@2.2.0': - resolution: {integrity: sha512-4x6M/ZSyoQy6fJeMArP0dvvNT4IOolfySyukuqqKhsLmSXDV4wGanqXIZ+xFihw3TlReS6JTa4hRG9nAZInpmw==} - '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} '@types/eslint@9.6.1': resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} - '@types/estree@1.0.7': - resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} - - '@types/express-serve-static-core@4.19.6': - resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} - - '@types/express@4.17.21': - resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} - - '@types/http-cache-semantics@4.0.4': - resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} - - '@types/http-errors@2.0.4': - resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} '@types/jquery-cropper@1.0.4': resolution: {integrity: sha512-YMyUoY+rhB8yc3xM1B/daNaSq5+q93rzvRx6HP8K9mmvXEviTH3/rldlYNCGd0TmE/kLlZYJsruYhu9wY350PA==} @@ -1051,66 +284,15 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/keygrip@1.0.6': - resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==} - - '@types/keyv@3.1.4': - resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} - - '@types/lodash@4.17.23': - resolution: {integrity: sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==} - - '@types/long@4.0.2': - resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} - - '@types/mime-types@2.1.4': - resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==} - - '@types/mime@1.3.5': - resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - - '@types/multer@1.4.12': - resolution: {integrity: sha512-pQ2hoqvXiJt2FP9WQVLPRO+AmiIm/ZYkavPlIQnx282u4ZrVdztx0pkh3jjpQt0Kz+YI0YhSG264y08UJKoUQg==} - - '@types/node-persist@3.1.8': - resolution: {integrity: sha512-QLidg6/SadZYPrTKxtxL1A85XBoQlG40bhoMdhu6DH6+eNCMr2j+RGfFZ9I9+IY8W/PDwQonJ+iBWD62jZjMfg==} - - '@types/node@16.9.1': - resolution: {integrity: sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==} + '@types/lodash@4.17.24': + resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} '@types/node@18.19.86': resolution: {integrity: sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==} - '@types/png-chunk-text@1.0.3': - resolution: {integrity: sha512-7keEFz73uNJ9Ar1XMCNnHEXT9pICJnouMQCCYgBEmHMgdkXaQzSTmSvr6tUDSqgdEgmlRAxZd97wprgliyZoCg==} - - '@types/png-chunks-extract@1.0.2': - resolution: {integrity: sha512-z6djfFIbrrddtunoMJBOPlyZrnmeuG1kkvHUNi2QfpOb+JMMLuLliHHTmMyRi7k7LiTAut0HbdGCF6ibDtQAHQ==} - - '@types/qs@6.9.18': - resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==} - - '@types/range-parser@1.2.7': - resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - - '@types/readdir-glob@1.1.5': - resolution: {integrity: sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==} - - '@types/response-time@2.3.8': - resolution: {integrity: sha512-7qGaNYvdxc0zRab8oHpYx7AW17qj+G0xuag1eCrw3M2VWPJQ/HyKaaghWygiaOUl0y9x7QGQwppDpqLJ5V9pzw==} - - '@types/responselike@1.0.3': - resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} - '@types/select2@4.0.63': resolution: {integrity: sha512-/DXUfPSj3iVTGlRYRYPCFKKSogAGP/j+Z0fIMXbBiBtmmZj0WH7vnfNuckafq9C43KnqPPQW2TI/Rj/vTSGnQQ==} - '@types/send@0.17.4': - resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} - - '@types/serve-static@1.15.7': - resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} - '@types/sizzle@2.3.9': resolution: {integrity: sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==} @@ -1120,21 +302,6 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@types/write-file-atomic@4.0.3': - resolution: {integrity: sha512-qdo+vZRchyJIHNeuI1nrpsLw+hnkgqP/8mlaN6Wle/NKhydHmUN9l4p3ZE8yP90AJNJW4uB8HQhedb4f1vNayQ==} - - '@types/yargs-parser@21.0.3': - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - - '@types/yargs@17.0.33': - resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - - '@types/yauzl@2.10.3': - resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - '@vue/compiler-core@3.5.33': resolution: {integrity: sha512-3PZLQwFw4Za3TC8t0FvTy3wI16Kt+pmwcgNZca4Pj9iWL2E72a/gZlpBtAJvEdDMdCxdG/qq0C7PN0bsJuv0Rw==} @@ -1240,32 +407,17 @@ packages: '@xtuc/long@4.2.2': resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} - '@zeldafan0225/ai_horde@5.2.0': - resolution: {integrity: sha512-IkFFwt8nTW+F87Kndl1b5ZQfZVgnTm2qf5By4M82fEH+KyHXvnkSTzOl/rUaqW0tjAXIyD+DM0D35TpdolPj4g==} - engines: {node: '>=18.0.0'} - - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + acorn-import-phases@1.0.4: + resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} + engines: {node: '>=10.13.0'} peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn: ^8.14.0 - acorn@8.14.1: - resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true - agent-base@7.1.3: - resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} - engines: {node: '>= 14'} - ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -1279,287 +431,42 @@ packages: peerDependencies: ajv: ^8.8.2 - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: '>=12'} - - ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - - any-base@1.1.0: - resolution: {integrity: sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==} - - app-root-path@3.1.0: - resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==} - engines: {node: '>= 6.0.0'} - - append-field@1.0.0: - resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} - - archiver-utils@5.0.2: - resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} - engines: {node: '>= 14'} - - archiver@7.0.1: - resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} - engines: {node: '>= 14'} - - are-docs-informative@0.0.2: - resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} - engines: {node: '>=14'} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - - asn1.js@4.10.1: - resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} - - assert@2.1.0: - resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} - - ast-types@0.13.4: - resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} - engines: {node: '>=4'} - - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - await-to-js@3.0.0: - resolution: {integrity: sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==} + baseline-browser-mapping@2.10.29: + resolution: {integrity: sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==} engines: {node: '>=6.0.0'} - - axios@0.26.1: - resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==} - - axios@1.8.4: - resolution: {integrity: sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==} - - b4a@1.6.7: - resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - bare-events@2.5.4: - resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - basic-ftp@5.0.5: - resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} - engines: {node: '>=10.0.0'} - - bing-translate-api@4.0.2: - resolution: {integrity: sha512-JJ8XUehnxzOhHU91oy86xEtp8OOMjVEjCZJX042fKxoO19NNvxJ5omeCcxQNFoPbDqVpBJwqiGVquL0oPdQm1Q==} - - bmp-js@0.1.0: - resolution: {integrity: sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==} - - bmp-ts@1.0.9: - resolution: {integrity: sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw==} - - bn.js@4.12.1: - resolution: {integrity: sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==} - - bn.js@5.2.1: - resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - - body-parser@1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + hasBin: true bowser@2.14.1: resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - - brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - - browserify-aes@1.2.0: - resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} - - browserify-cipher@1.0.1: - resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} - - browserify-des@1.0.2: - resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} - - browserify-rsa@4.1.1: - resolution: {integrity: sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==} - engines: {node: '>= 0.10'} - - browserify-sign@4.2.3: - resolution: {integrity: sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==} - engines: {node: '>= 0.12'} - - browserslist@4.24.4: - resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - - buffer-crc32@1.0.0: - resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} - engines: {node: '>=8.0.0'} - - buffer-equal@0.0.1: - resolution: {integrity: sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==} - engines: {node: '>=0.4.0'} - buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - buffer-xor@1.0.3: - resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + caniuse-lite@1.0.30001792: + resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - - busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - cacheable-lookup@5.0.4: - resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} - engines: {node: '>=10.6.0'} - - cacheable-request@7.0.4: - resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} - engines: {node: '>=8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - caniuse-lite@1.0.30001714: - resolution: {integrity: sha512-mtgapdwDLSSBnCI3JokHM7oEQBLxiJKVRtg10AxM1AyeiKcM96f0Mkbqeq+1AbiCtvMcHRulAAEMu693JrSWqg==} - - centra@2.7.0: - resolution: {integrity: sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==} - - chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chalk@5.4.1: - resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - - cheerio-select@2.1.0: - resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} - - cheerio@1.0.0: - resolution: {integrity: sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==} - engines: {node: '>=18.17'} - - chevrotain@11.1.1: - resolution: {integrity: sha512-f0yv5CPKaFxfsPTBzX7vGuim4oIC1/gcS7LUGdBSwl2dU6+FON6LVUksdOo1qJjoUvXNn45urgh8C+0a24pACQ==} + chevrotain@11.2.0: + resolution: {integrity: sha512-mHCHTxM51nCklUw9RzRVc0DLjAh/SAUPM4k/zMInlTIo25ldWXOZoPt7XEIk/LwoT4lFVmJcu9g5MHtx371x3A==} chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} - cipher-base@1.0.6: - resolution: {integrity: sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==} - engines: {node: '>= 0.10'} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - clone-deep@4.0.1: resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} engines: {node: '>=6'} - clone-response@1.0.3: - resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} - - color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - command-exists@1.2.9: - resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} - commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} @@ -1571,276 +478,31 @@ packages: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} - comment-parser@1.4.1: - resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} - engines: {node: '>= 12.0.0'} - - compress-commons@6.0.2: - resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} - engines: {node: '>= 14'} - - compressible@2.0.18: - resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} - engines: {node: '>= 0.6'} - - compression@1.8.0: - resolution: {integrity: sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==} - engines: {node: '>= 0.8.0'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - concat-stream@1.6.2: - resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} - engines: {'0': node >= 0.8} - - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - cookie-parser@1.4.7: - resolution: {integrity: sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==} - engines: {node: '>= 0.8.0'} - - cookie-session@2.1.0: - resolution: {integrity: sha512-u73BDmR8QLGcs+Lprs0cfbcAPKl2HnPcjpwRXT41sEV4DRJ2+W0vJEEZkG31ofkx+HZflA70siRIjiTdIodmOQ==} - engines: {node: '>= 0.10'} - - cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - - cookie@0.7.1: - resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} - engines: {node: '>= 0.6'} - - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - - cookies@0.9.1: - resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==} - engines: {node: '>= 0.8'} - - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - - cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} - engines: {node: '>= 0.10'} - - crc-32@0.3.0: - resolution: {integrity: sha512-kucVIjOmMc1f0tv53BJ/5WIX+MGLcKuoBhnGqQrgKJNqLByb/sVMWfW/Aw6hw0jgcqjJ2pi9E5y32zOIpaUlsA==} - engines: {node: '>=0.8'} - - crc-32@1.2.2: - resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} - engines: {node: '>=0.8'} - hasBin: true - - crc32-stream@6.0.0: - resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} - engines: {node: '>= 14'} - - crc@4.3.2: - resolution: {integrity: sha512-uGDHf4KLLh2zsHa8D8hIQ1H/HtFQhyHrc0uhHBcoKGol/Xnb+MPYfUMw7cvON6ze/GUESTudKayDcJC5HnJv1A==} - engines: {node: '>=12'} - peerDependencies: - buffer: '>=6.0.3' - peerDependenciesMeta: - buffer: - optional: true - - create-ecdh@4.0.4: - resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} - - create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} - - create-hmac@1.1.7: - resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - crypto-browserify@3.12.1: - resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==} - engines: {node: '>= 0.10'} - - csrf-sync@4.1.0: - resolution: {integrity: sha512-bEA+AwaBbXkf6k4UHg0JGuGpuVs+HiOX4KjoZmbvxIhtKl+8ND7OOElgbaR59qSPtvfvXIyCnmAPYzsND+EZhA==} - - css-select@5.1.0: - resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} - - css-what@6.1.0: - resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} - engines: {node: '>= 6'} - csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} - - data-uri-to-buffer@6.0.2: - resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} - engines: {node: '>= 14'} - - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - defer-to-connect@2.0.1: - resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} - engines: {node: '>=10'} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-lazy-prop@2.0.0: - resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} - engines: {node: '>=8'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - - degenerator@5.0.1: - resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} - engines: {node: '>= 14'} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - des.js@1.1.0: - resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} - - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - diff-match-patch@1.0.5: resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} - diffie-hellman@5.0.3: - resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} - - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - - dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} - - dom-walk@0.1.2: - resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} - - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - - domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} - - dompurify@3.3.1: - resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==} - - domutils@3.2.2: - resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - - dotenv@8.6.0: - resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} - engines: {node: '>=10'} + dompurify@3.4.3: + resolution: {integrity: sha512-VVwJidIJcp1hpg2OMXML3ZVRPYSZiq4aX7qBh83BSIpOaRDqI+qxhXjjIWnpzkOXhmp0L81lnoME1mnCc9H48A==} droll@0.2.1: resolution: {integrity: sha512-fXxtxZSwGK6afeG18Vk6q/8LQDAnIylsvk/2tQhHwDOJmdB/x+YL9GLoSZUZXJkQ8LrBcyU/1EoIL1eSlpDMsg==} engines: {node: '>=0.8.0'} hasBin: true - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} + electron-to-chromium@1.5.354: + resolution: {integrity: sha512-JaBHwWcfIdmSAfWM5l3uwjGd431j8YEMikZ+K/2nXVuBqJKyZ0f+2h4n4JY5AyNiZmnY9qQr2RU3v9DxDmHMNg==} - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - electron-to-chromium@1.5.139: - resolution: {integrity: sha512-GGnRYOTdN5LYpwbIr0rwP/ZHOQSvAF6TG0LSzp28uCBb9JiXHJGmaaKw29qjNJc5bGnnp6kXJqRnGMQoELwi5w==} - - elliptic@6.6.1: - resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - encoding-sniffer@0.2.0: - resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==} - - end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - - enhanced-resolve@5.18.1: - resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} + enhanced-resolve@5.21.3: + resolution: {integrity: sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==} engines: {node: '>=10.13.0'} - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} @@ -1850,93 +512,17 @@ packages: engines: {node: '>=4'} hasBin: true - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-module-lexer@1.6.0: - resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} - es-module-lexer@2.0.0: resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - escodegen@2.1.0: - resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} - engines: {node: '>=6.0'} - hasBin: true - - eslint-plugin-jsdoc@48.11.0: - resolution: {integrity: sha512-d12JHJDPNo7IFwTOAItCeJY1hcqoIxE0lHA8infQByLilQ9xkqrRa6laWCnsuCrf+8rUnvxXY1XuTbibRBNylA==} - engines: {node: '>=18'} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@4.2.0: - resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. - hasBin: true - - espree@10.3.0: - resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} - esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -1952,44 +538,13 @@ packages: estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - evp_bytestokey@1.0.3: - resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} - - exif-parser@0.1.12: - resolution: {integrity: sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==} - - express@4.21.2: - resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} - engines: {node: '>= 0.10.0'} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-fifo@1.3.2: - resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.0.6: resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} @@ -1997,86 +552,17 @@ packages: resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} engines: {node: '>= 4.9.1'} - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} - - fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - - fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} - - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - - file-type@16.5.4: - resolution: {integrity: sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==} - engines: {node: '>=10'} - - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} - engines: {node: '>= 0.8'} + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - flat@5.0.2: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true - flatbuffers@1.12.0: - resolution: {integrity: sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==} - - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - - follow-redirects@1.15.9: - resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - - form-data@4.0.2: - resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} - engines: {node: '>= 6'} - - formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} - - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -2084,285 +570,49 @@ packages: resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} engines: {node: '>=10'} - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - get-stream@5.2.0: - resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} - engines: {node: '>=8'} - - get-uri@6.0.4: - resolution: {integrity: sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==} - engines: {node: '>= 14'} - - gifwrap@0.10.1: - resolution: {integrity: sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw==} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} - hasBin: true - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - - global@4.4.0: - resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==} - - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - - google-translate-api-browser@3.0.1: - resolution: {integrity: sha512-KTLodkyGBWMK9IW6QIeJ2zCuju4Z0CLpbkADKo+yLhbSTD4l+CXXpQ/xaynGVAzeBezzJG6qn8MLeqOq3SmW0A==} - - google-translate-api-x@10.7.2: - resolution: {integrity: sha512-GSmbvGMcnULaih2NFgD4Y6840DLAMot90mLWgwoB+FG/QpetyZkFrZkxop8ZxXgOAQXGskFOhGJady8nA6ZJ2g==} - engines: {node: '>=14.0.0'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - got@11.8.6: - resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} - engines: {node: '>=10.19.0'} - - gpt-3-encoder@1.1.4: - resolution: {integrity: sha512-fSQRePV+HUAhCn7+7HL7lNIXNm6eaFWFbNLOOGtmSJ0qJycyQvj60OvRlH7mee8xAMjBDNRdMXlMwjAbMTDjkg==} - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - guid-typescript@1.0.9: - resolution: {integrity: sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==} - - handlebars@4.7.8: - resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + handlebars@4.7.9: + resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} engines: {node: '>=0.4.7'} hasBin: true - has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hash-base@3.0.5: - resolution: {integrity: sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==} - engines: {node: '>= 0.10'} - - hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - helmet@7.2.0: - resolution: {integrity: sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==} - engines: {node: '>=16.0.0'} - highlight.js@11.11.1: resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} engines: {node: '>=12.0.0'} - hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - - html-entities@2.6.0: - resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} - - htmlparser2@9.1.0: - resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} - - http-cache-semantics@4.1.1: - resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} - - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - - http2-wrapper@1.0.3: - resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} - engines: {node: '>=10.19.0'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - image-q@4.0.0: - resolution: {integrity: sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==} - immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - import-local@3.2.0: resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} engines: {node: '>=8'} hasBin: true - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - inflight@1.0.6: - resolution: {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. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - interpret@3.1.1: resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} engines: {node: '>=10.13.0'} - ip-address@9.0.5: - resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} - engines: {node: '>= 12'} - - ip-matching@2.1.2: - resolution: {integrity: sha512-/ok+VhKMasgR5gvTRViwRFQfc0qYt9Vdowg6TO4/pFlDCob5ZjGPkwuOoQVCd5OrMm20zqh+1vA8KLJZTeWudg==} - - ip-regex@5.0.0: - resolution: {integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - - ipaddr.js@2.2.0: - resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} - engines: {node: '>= 10'} - - is-arguments@1.2.0: - resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} - engines: {node: '>= 0.4'} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} - is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true - - is-docker@3.0.0: - resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hasBin: true - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-function@1.0.2: - resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==} - - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} - engines: {node: '>= 0.4'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-nan@1.3.2: - resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} - engines: {node: '>= 0.4'} - - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - is-plain-object@2.0.4: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - - is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} - - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -2370,78 +620,25 @@ packages: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} - isomorphic-fetch@3.0.0: - resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==} - - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} - jimp@0.22.12: - resolution: {integrity: sha512-R5jZaYDnfkxKJy1dwLpj/7cvyjxiclxU3F4TrI/J4j2rS0niq6YDUMoPn5hs8GDpO+OZGo7Ky057CRtWesyhfg==} - - jpeg-js@0.4.4: - resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} - - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - - jsbn@1.1.0: - resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - - jsdoc-type-pratt-parser@4.0.0: - resolution: {integrity: sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==} - engines: {node: '>=12.0.0'} - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-colorizer@2.2.2: - resolution: {integrity: sha512-56oZtwV1piXrQnRNTtJeqRv+B9Y/dXAYLqBBaYl/COcUdoZxgLBLAO88+CnkbT6MxNs0c5E9mPBIb2sFcNz3vw==} - - json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + js-sha256@0.11.1: + resolution: {integrity: sha512-o6WSo/LUvY2uC4j7mO50a2ms7E/EAdbP0swigLV+nzHKTTaYnaLIWJ02VdXrsJX0vGedDESQnLsOekr94ryfjg==} json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - keygrip@1.1.0: - resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==} - engines: {node: '>= 0.6'} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - lazystream@1.0.1: - resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} - engines: {node: '>= 0.6.3'} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - lie@3.1.1: resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==} - load-bmfont@1.4.2: - resolution: {integrity: sha512-qElWkmjW9Oq1F9EI5Gt7aD9zcdHb9spJCW1L/dmPf7KzCCEJxq8nhHz5eCgI9aMf7vrG/wyaCqdsI+Iy9ZTlog==} - - loader-runner@4.3.0: - resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + loader-runner@4.3.2: + resolution: {integrity: sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==} engines: {node: '>=6.11.5'} localforage@1.10.0: @@ -2451,347 +648,58 @@ packages: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - lodash-es@4.17.23: resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} - lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - - long@4.0.0: - resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} - - lowercase-keys@2.0.0: - resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} - engines: {node: '>=8'} - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} - - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} - merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - - miller-rabin@4.0.1: - resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} - hasBin: true - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - mime-db@1.54.0: resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} engines: {node: '>= 0.6'} - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - - mime@3.0.0: - resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} - engines: {node: '>=10.0.0'} - hasBin: true - - mimic-response@1.0.1: - resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} - engines: {node: '>=4'} - - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - - min-document@2.19.0: - resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==} - - minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - - minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} - - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - moment@2.30.1: resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} morphdom@2.7.8: resolution: {integrity: sha512-D/fR4xgGUyVRbdMGU6Nejea1RFzYxYtyurG4Fbv2Fi/daKlWKuXGLOdXtl+3eIwL110cI2hz1ZojGICjjFLgTg==} - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - multer@1.4.5-lts.2: - resolution: {integrity: sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==} - engines: {node: '>= 6.0.0'} - nanoid@3.3.12: resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} - neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - netmask@2.0.2: - resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} - engines: {node: '>= 0.4.0'} - - node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - deprecated: Use your platform's native DOMException instead - - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - - node-fetch@3.3.2: - resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - node-persist@4.0.4: - resolution: {integrity: sha512-8sPAz/7tw1mCCc8xBG4f0wi+flHkSSgQeX998iQ75Pu27evA6UUWCjSE7xnrYTg2q33oU5leJ061EKPDv6BocQ==} - engines: {node: '>=10.12.0'} - - node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - normalize-url@6.1.0: - resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} - engines: {node: '>=10'} - - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - object-is@1.1.6: - resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} - engines: {node: '>= 0.4'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} - - omggif@1.0.10: - resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - on-headers@1.0.2: - resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} - engines: {node: '>= 0.8'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onnx-proto@4.0.4: - resolution: {integrity: sha512-aldMOB3HRoo6q/phyB6QRQxSt895HNNw82BNyZ2CMh4bjeKv7g/c+VpAFtJuEMVfYLMbRx61hbuqnKceLeDcDA==} - - onnxruntime-common@1.14.0: - resolution: {integrity: sha512-3LJpegM2iMNRX2wUmtYfeX/ytfOzNwAWKSq1HbRrKc9+uqG/FsEA0bbKZl1btQeZaXhC26l44NWpNUeXPII7Ew==} - - onnxruntime-web@1.14.0: - resolution: {integrity: sha512-Kcqf43UMfW8mCydVGcX9OMXI2VN17c0p6XvR7IPSZzBf/6lteBzXHvcEVWDPmCKuGombl997HgLqj91F11DzXw==} - - open@8.4.2: - resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} - engines: {node: '>=12'} - - openai@3.3.0: - resolution: {integrity: sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ==} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - os-browserify@0.3.0: - resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} - - p-cancelable@2.1.1: - resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} - engines: {node: '>=8'} + node-releases@2.0.44: + resolution: {integrity: sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==} p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - pac-proxy-agent@7.2.0: - resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==} - engines: {node: '>= 14'} - - pac-resolver@7.0.1: - resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} - engines: {node: '>= 14'} - - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - - pako@1.0.11: - resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - parse-asn1@5.1.7: - resolution: {integrity: sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==} - engines: {node: '>= 0.10'} - - parse-bmfont-ascii@1.0.6: - resolution: {integrity: sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==} - - parse-bmfont-binary@1.0.6: - resolution: {integrity: sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==} - - parse-bmfont-xml@1.1.6: - resolution: {integrity: sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==} - - parse-headers@2.0.6: - resolution: {integrity: sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==} - - parse-imports@2.2.1: - resolution: {integrity: sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==} - engines: {node: '>= 18'} - - parse5-htmlparser2-tree-adapter@7.1.0: - resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} - - parse5-parser-stream@7.1.2: - resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} - - parse5@7.2.1: - resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - path-browserify@1.0.1: - resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -2799,176 +707,29 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - - path-to-regexp@0.1.12: - resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - - pbkdf2@3.1.2: - resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} - engines: {node: '>=0.12'} - - peek-readable@4.1.0: - resolution: {integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==} - engines: {node: '>=8'} - - pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - - phin@3.7.1: - resolution: {integrity: sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==} - engines: {node: '>= 8'} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - pixelmatch@4.0.2: - resolution: {integrity: sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==} - hasBin: true - pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} - platform@1.3.6: - resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==} - - png-chunk-text@1.0.0: - resolution: {integrity: sha512-DEROKU3SkkLGWNMzru3xPVgxyd48UGuMSZvioErCure6yhOc/pRH2ZV+SEn7nmaf7WNf3NdIpH+UTrRdKyq9Lw==} - - png-chunks-extract@1.0.0: - resolution: {integrity: sha512-ZiVwF5EJ0DNZyzAqld8BP1qyJBaGOFaq9zl579qfbkcmOwWLLO4I9L8i2O4j3HkI6/35i0nKG2n+dZplxiT89Q==} - - pngjs@3.4.0: - resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} - engines: {node: '>=4.0.0'} - - pngjs@6.0.0: - resolution: {integrity: sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==} - engines: {node: '>=12.13.0'} - - pngjs@7.0.0: - resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} - engines: {node: '>=14.19.0'} - - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - postcss@8.5.13: resolution: {integrity: sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==} engines: {node: ^10 || ^12 || >=14} - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - - protobufjs@6.11.4: - resolution: {integrity: sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==} - hasBin: true - - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - - proxy-agent@6.5.0: - resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} - engines: {node: '>= 14'} - - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - - public-encrypt@4.0.3: - resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} - - pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} - engines: {node: '>=0.6'} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} - - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - - randomfill@1.0.4: - resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - rate-limiter-flexible@5.0.5: - resolution: {integrity: sha512-+/dSQfo+3FYwYygUs/V2BBdwGa9nFtakDwKt4l0bnvNB53TNT++QSFewwHX9qXrZJuMe9j+TUaU21lm5ARgqdQ==} - - raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} - - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - readable-stream@4.7.0: - resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - readable-web-to-node-stream@3.0.4: - resolution: {integrity: sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==} - engines: {node: '>=8'} - - readdir-glob@1.1.3: - resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} - rechoir@0.8.0: resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} engines: {node: '>= 10.13.0'} - regenerator-runtime@0.13.11: - resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} @@ -2978,81 +739,13 @@ packages: engines: {node: '>= 0.4'} hasBin: true - response-time@2.3.3: - resolution: {integrity: sha512-SsjjOPHl/FfrTQNgmc5oen8Hr1Jxpn6LlHNXxCIFdYMHuK1kMeYMobb9XN3mvxaGQm3dbegqYFMX4+GDORfbWg==} - engines: {node: '>= 0.8.0'} - - responselike@2.0.1: - resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - sanitize-filename@1.6.3: - resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} - - sax@1.4.1: - resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} - - schema-utils@4.3.0: - resolution: {integrity: sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==} + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} seedrandom@3.0.5: resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==} - semver@7.7.1: - resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} - engines: {node: '>=10'} - hasBin: true - - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} - engines: {node: '>= 0.8.0'} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} - hasBin: true - shallow-clone@3.0.1: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} @@ -3069,50 +762,6 @@ packages: resolution: {integrity: sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==} hasBin: true - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - sillytavern-transformers@2.14.6: - resolution: {integrity: sha512-Tpu3lcDfa3vQB/wRgF+7ZG8ZNtYygT6vEQs9+4BpXLghVanx6ic7rBSxmTxx9Sm90G1P3W8mxoVkzfs8KAvMiA==} - - simple-git@3.27.0: - resolution: {integrity: sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA==} - - slashes@3.0.12: - resolution: {integrity: sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==} - - slidetoggle@4.0.0: - resolution: {integrity: sha512-6qvrOS1dnDFEr41UEEFFRQE8nswaAFIYZAHer6dVlznRIjHyCISjNJoxIn5U5QlAbZfBBxTELQk4jS7miHto1A==} - - smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - - socks-proxy-agent@8.0.5: - resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} - engines: {node: '>= 14'} - - socks@2.8.4: - resolution: {integrity: sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -3124,70 +773,6 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} - - spdx-expression-parse@4.0.0: - resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} - - spdx-license-ids@3.0.21: - resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} - - sprintf-js@1.1.3: - resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - - stream-browserify@3.0.0: - resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} - - streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} - - streamx@2.22.0: - resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - strtok3@6.3.0: - resolution: {integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==} - engines: {node: '>=10'} - - supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} @@ -3196,30 +781,50 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - synckit@0.9.2: - resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} - engines: {node: ^14.18.0 || >=16.0.0} - - tapable@2.2.1: - resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} - tar-stream@3.1.7: - resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} - - terser-webpack-plugin@5.3.14: - resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} + terser-webpack-plugin@5.6.0: + resolution: {integrity: sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==} engines: {node: '>= 10.13.0'} peerDependencies: + '@minify-html/node': '*' '@swc/core': '*' + '@swc/css': '*' + '@swc/html': '*' + clean-css: '*' + cssnano: '*' + csso: '*' esbuild: '*' + html-minifier-terser: '*' + lightningcss: '*' + postcss: '*' uglify-js: '*' webpack: ^5.1.0 peerDependenciesMeta: + '@minify-html/node': + optional: true '@swc/core': optional: true + '@swc/css': + optional: true + '@swc/html': + optional: true + clean-css: + optional: true + cssnano: + optional: true + csso: + optional: true esbuild: optional: true + html-minifier-terser: + optional: true + lightningcss: + optional: true + postcss: + optional: true uglify-js: optional: true @@ -3228,57 +833,6 @@ packages: engines: {node: '>=10'} hasBin: true - text-decoder@1.2.3: - resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} - - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - - tiktoken@1.0.22: - resolution: {integrity: sha512-PKvy1rVF1RibfF3JlXBSP0Jrcw2uq3yXdgcEXtKTYn3QJ/cBRBHDnrJ5jHky+MENZ6DIPwNUGWpkVx+7joCpNA==} - - timm@1.7.1: - resolution: {integrity: sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==} - - tinycolor2@1.6.0: - resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - token-types@4.2.1: - resolution: {integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==} - engines: {node: '>=10'} - - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - truncate-utf8-bytes@1.0.2: - resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - tsscmp@1.0.6: - resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} - engines: {node: '>=0.6.x'} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - - typedarray@0.0.6: - resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -3292,55 +846,12 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - undici@6.21.2: - resolution: {integrity: sha512-uROZWze0R0itiAKVPsYhFov9LxrPMHLMEQFszeI2gCN6bnIIZ8twzBCJcN2LJrBBLfrP0t1FW0g+JmKVl8Vk1g==} - engines: {node: '>=18.17'} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - url-join@5.0.0: - resolution: {integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - utf8-byte-length@1.0.5: - resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} - - utif2@4.1.0: - resolution: {integrity: sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - util@0.12.5: - resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - - vectra@0.2.2: - resolution: {integrity: sha512-Z1d29Zil+dlA9/Qz4VJB3zcWjIARY8QH5xQEnHmGgmTUP58cPRV8NK7P0QH91IRs0RvAWrYiQf9Y5JqQo0vJlQ==} - hasBin: true - vue@3.5.33: resolution: {integrity: sha512-1AgChhx5w3ALgT4oK3acm2Es/7jyZhWSVUfs3rOBlGQC0rjEDkS7G4lWlJJGGNQD+BV3reCwbQrOe1mPNwKHBQ==} peerDependencies: @@ -3349,25 +860,10 @@ packages: typescript: optional: true - wasm-feature-detect@1.8.0: - resolution: {integrity: sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==} - - watchpack@2.4.2: - resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} engines: {node: '>=10.13.0'} - wavefile@11.0.0: - resolution: {integrity: sha512-/OBiAALgWU24IG7sC84cDO/KfFuvajWc5Uec0oV2zrpOOZZDgGdOwHwgEzOrwh8jkubBk7PtZfQBIcI1OaE5Ng==} - engines: {node: '>=8'} - hasBin: true - - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} - engines: {node: '>= 8'} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - webpack-cli@5.1.4: resolution: {integrity: sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==} engines: {node: '>=14.15.0'} @@ -3389,12 +885,12 @@ packages: resolution: {integrity: sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==} engines: {node: '>=10.0.0'} - webpack-sources@3.2.3: - resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} + webpack-sources@3.4.1: + resolution: {integrity: sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==} engines: {node: '>=10.13.0'} - webpack@5.99.6: - resolution: {integrity: sha512-TJOLrJ6oeccsGWPl7ujCYuc0pIq2cNsuD6GZDma8i5o5Npvcco/z+NKvZSFsP0/x6SShVb0+X2JK/JHUjKY9dQ==} + webpack@5.106.2: + resolution: {integrity: sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -3403,24 +899,6 @@ packages: webpack-cli: optional: true - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - - whatwg-fetch@3.6.20: - resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} - - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - - which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} - engines: {node: '>= 0.4'} - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -3429,99 +907,13 @@ packages: wildcard@2.0.1: resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - write-file-atomic@5.0.1: - resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - ws@8.18.1: - resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - xhr@2.6.0: - resolution: {integrity: sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==} - - xml-parse-from-string@1.0.1: - resolution: {integrity: sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==} - - xml2js@0.5.0: - resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} - engines: {node: '>=4.0.0'} - - xmlbuilder@11.0.1: - resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} - engines: {node: '>=4.0'} - - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yaml@2.8.2: - resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} - engines: {node: '>= 14.6'} - hasBin: true - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - zip-stream@6.0.1: - resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} - engines: {node: '>= 14'} - - zod@3.24.3: - resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==} - snapshots: '@adobe/css-tools@4.4.4': {} - '@agnai/sentencepiece-js@1.1.1': - dependencies: - app-root-path: 3.1.0 - - '@agnai/web-tokenizers@0.1.3': {} - '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.28.5': {} @@ -3535,480 +927,31 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@chevrotain/cst-dts-gen@11.1.1': + '@chevrotain/cst-dts-gen@11.2.0': dependencies: - '@chevrotain/gast': 11.1.1 - '@chevrotain/types': 11.1.1 + '@chevrotain/gast': 11.2.0 + '@chevrotain/types': 11.2.0 lodash-es: 4.17.23 - '@chevrotain/gast@11.1.1': + '@chevrotain/gast@11.2.0': dependencies: - '@chevrotain/types': 11.1.1 + '@chevrotain/types': 11.2.0 lodash-es: 4.17.23 - '@chevrotain/regexp-to-ast@11.1.1': {} + '@chevrotain/regexp-to-ast@11.2.0': {} - '@chevrotain/types@11.1.1': {} + '@chevrotain/types@11.2.0': {} - '@chevrotain/utils@11.1.1': {} + '@chevrotain/utils@11.2.0': {} '@discoveryjs/json-ext@0.5.7': {} - '@es-joy/jsdoccomment@0.46.0': - dependencies: - comment-parser: 1.4.1 - esquery: 1.6.0 - jsdoc-type-pratt-parser: 4.0.0 - - '@eslint-community/eslint-utils@4.6.1(eslint@8.57.1)': - dependencies: - eslint: 8.57.1 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.1': {} - - '@eslint/eslintrc@2.1.4': - dependencies: - ajv: 6.12.6 - debug: 4.4.0 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@8.57.1': {} - - '@huggingface/jinja@0.1.3': {} - - '@humanwhocodes/config-array@0.13.0': - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.0 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/object-schema@2.0.3': {} - '@iconfu/svg-inject@1.2.3': {} - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@jimp/bmp@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - bmp-js: 0.1.0 - - '@jimp/core@0.22.12': - dependencies: - '@jimp/utils': 0.22.12 - any-base: 1.1.0 - buffer: 5.7.1 - exif-parser: 0.1.12 - file-type: 16.5.4 - isomorphic-fetch: 3.0.0 - pixelmatch: 4.0.2 - tinycolor2: 1.6.0 - transitivePeerDependencies: - - encoding - - '@jimp/core@1.6.0': - dependencies: - '@jimp/file-ops': 1.6.0 - '@jimp/types': 1.6.0 - '@jimp/utils': 1.6.0 - await-to-js: 3.0.0 - exif-parser: 0.1.12 - file-type: 16.5.4 - mime: 3.0.0 - - '@jimp/custom@0.22.12': - dependencies: - '@jimp/core': 0.22.12 - transitivePeerDependencies: - - encoding - - '@jimp/file-ops@1.6.0': {} - - '@jimp/gif@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - gifwrap: 0.10.1 - omggif: 1.0.10 - - '@jimp/jpeg@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - jpeg-js: 0.4.4 - - '@jimp/js-bmp@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/types': 1.6.0 - '@jimp/utils': 1.6.0 - bmp-ts: 1.0.9 - - '@jimp/js-gif@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/types': 1.6.0 - gifwrap: 0.10.1 - omggif: 1.0.10 - - '@jimp/js-jpeg@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/types': 1.6.0 - jpeg-js: 0.4.4 - - '@jimp/js-png@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/types': 1.6.0 - pngjs: 7.0.0 - - '@jimp/js-tiff@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/types': 1.6.0 - utif2: 4.1.0 - - '@jimp/plugin-blit@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - - '@jimp/plugin-blit@1.6.0': - dependencies: - '@jimp/types': 1.6.0 - '@jimp/utils': 1.6.0 - zod: 3.24.3 - - '@jimp/plugin-blur@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - - '@jimp/plugin-circle@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - - '@jimp/plugin-circle@1.6.0': - dependencies: - '@jimp/types': 1.6.0 - zod: 3.24.3 - - '@jimp/plugin-color@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - tinycolor2: 1.6.0 - - '@jimp/plugin-color@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/types': 1.6.0 - '@jimp/utils': 1.6.0 - tinycolor2: 1.6.0 - zod: 3.24.3 - - '@jimp/plugin-contain@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-blit@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-scale@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12)))': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/plugin-blit': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-resize': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-scale': 0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12)) - '@jimp/utils': 0.22.12 - - '@jimp/plugin-contain@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/plugin-blit': 1.6.0 - '@jimp/plugin-resize': 1.6.0 - '@jimp/types': 1.6.0 - '@jimp/utils': 1.6.0 - zod: 3.24.3 - - '@jimp/plugin-cover@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-crop@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-scale@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12)))': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/plugin-crop': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-resize': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-scale': 0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12)) - '@jimp/utils': 0.22.12 - - '@jimp/plugin-cover@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/plugin-crop': 1.6.0 - '@jimp/plugin-resize': 1.6.0 - '@jimp/types': 1.6.0 - zod: 3.24.3 - - '@jimp/plugin-crop@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - - '@jimp/plugin-crop@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/types': 1.6.0 - '@jimp/utils': 1.6.0 - zod: 3.24.3 - - '@jimp/plugin-displace@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - - '@jimp/plugin-displace@1.6.0': - dependencies: - '@jimp/types': 1.6.0 - '@jimp/utils': 1.6.0 - zod: 3.24.3 - - '@jimp/plugin-dither@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - - '@jimp/plugin-fisheye@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - - '@jimp/plugin-fisheye@1.6.0': - dependencies: - '@jimp/types': 1.6.0 - '@jimp/utils': 1.6.0 - zod: 3.24.3 - - '@jimp/plugin-flip@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-rotate@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-blit@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-crop@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12)))': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/plugin-rotate': 0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-blit@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-crop@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12)) - '@jimp/utils': 0.22.12 - - '@jimp/plugin-flip@1.6.0': - dependencies: - '@jimp/types': 1.6.0 - zod: 3.24.3 - - '@jimp/plugin-gaussian@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - - '@jimp/plugin-hash@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/js-bmp': 1.6.0 - '@jimp/js-jpeg': 1.6.0 - '@jimp/js-png': 1.6.0 - '@jimp/js-tiff': 1.6.0 - '@jimp/plugin-color': 1.6.0 - '@jimp/plugin-resize': 1.6.0 - '@jimp/types': 1.6.0 - '@jimp/utils': 1.6.0 - any-base: 1.1.0 - - '@jimp/plugin-invert@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - - '@jimp/plugin-mask@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - - '@jimp/plugin-mask@1.6.0': - dependencies: - '@jimp/types': 1.6.0 - zod: 3.24.3 - - '@jimp/plugin-normalize@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - - '@jimp/plugin-print@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-blit@0.22.12(@jimp/custom@0.22.12))': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/plugin-blit': 0.22.12(@jimp/custom@0.22.12) - '@jimp/utils': 0.22.12 - load-bmfont: 1.4.2 - transitivePeerDependencies: - - debug - - '@jimp/plugin-quantize@1.6.0': - dependencies: - image-q: 4.0.0 - zod: 3.24.3 - - '@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - - '@jimp/plugin-resize@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/types': 1.6.0 - zod: 3.24.3 - - '@jimp/plugin-rotate@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-blit@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-crop@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12))': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/plugin-blit': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-crop': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-resize': 0.22.12(@jimp/custom@0.22.12) - '@jimp/utils': 0.22.12 - - '@jimp/plugin-rotate@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/plugin-crop': 1.6.0 - '@jimp/plugin-resize': 1.6.0 - '@jimp/types': 1.6.0 - '@jimp/utils': 1.6.0 - zod: 3.24.3 - - '@jimp/plugin-scale@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12))': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/plugin-resize': 0.22.12(@jimp/custom@0.22.12) - '@jimp/utils': 0.22.12 - - '@jimp/plugin-shadow@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-blur@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12))': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/plugin-blur': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-resize': 0.22.12(@jimp/custom@0.22.12) - '@jimp/utils': 0.22.12 - - '@jimp/plugin-threshold@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-color@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12))': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/plugin-color': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-resize': 0.22.12(@jimp/custom@0.22.12) - '@jimp/utils': 0.22.12 - - '@jimp/plugin-threshold@1.6.0': - dependencies: - '@jimp/core': 1.6.0 - '@jimp/plugin-color': 1.6.0 - '@jimp/plugin-hash': 1.6.0 - '@jimp/types': 1.6.0 - '@jimp/utils': 1.6.0 - zod: 3.24.3 - - '@jimp/plugins@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/plugin-blit': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-blur': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-circle': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-color': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-contain': 0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-blit@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-scale@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12))) - '@jimp/plugin-cover': 0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-crop@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-scale@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12))) - '@jimp/plugin-crop': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-displace': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-dither': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-fisheye': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-flip': 0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-rotate@0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-blit@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-crop@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12))) - '@jimp/plugin-gaussian': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-invert': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-mask': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-normalize': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-print': 0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-blit@0.22.12(@jimp/custom@0.22.12)) - '@jimp/plugin-resize': 0.22.12(@jimp/custom@0.22.12) - '@jimp/plugin-rotate': 0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-blit@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-crop@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12)) - '@jimp/plugin-scale': 0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12)) - '@jimp/plugin-shadow': 0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-blur@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12)) - '@jimp/plugin-threshold': 0.22.12(@jimp/custom@0.22.12)(@jimp/plugin-color@0.22.12(@jimp/custom@0.22.12))(@jimp/plugin-resize@0.22.12(@jimp/custom@0.22.12)) - timm: 1.7.1 - transitivePeerDependencies: - - debug - - '@jimp/png@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/utils': 0.22.12 - pngjs: 6.0.0 - - '@jimp/tiff@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/custom': 0.22.12 - utif2: 4.1.0 - - '@jimp/types@0.22.12(@jimp/custom@0.22.12)': - dependencies: - '@jimp/bmp': 0.22.12(@jimp/custom@0.22.12) - '@jimp/custom': 0.22.12 - '@jimp/gif': 0.22.12(@jimp/custom@0.22.12) - '@jimp/jpeg': 0.22.12(@jimp/custom@0.22.12) - '@jimp/png': 0.22.12(@jimp/custom@0.22.12) - '@jimp/tiff': 0.22.12(@jimp/custom@0.22.12) - timm: 1.7.1 - - '@jimp/types@1.6.0': - dependencies: - zod: 3.24.3 - - '@jimp/utils@0.22.12': - dependencies: - regenerator-runtime: 0.13.11 - - '@jimp/utils@1.6.0': - dependencies: - '@jimp/types': 1.6.0 - tinycolor2: 1.6.0 - - '@jimp/wasm-avif@1.6.0': - dependencies: - '@jsquash/avif': 1.3.0 - zod: 3.24.3 - - '@jimp/wasm-jpeg@1.6.0': - dependencies: - '@jsquash/jpeg': 1.5.0 - zod: 3.24.3 - - '@jimp/wasm-png@1.6.0': - dependencies: - '@jsquash/oxipng': 2.3.0 - '@jsquash/png': 3.0.1 - zod: 3.24.3 - - '@jimp/wasm-webp@1.6.0': - dependencies: - '@jsquash/webp': 1.4.0 - zod: 3.24.3 - '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.2': {} @@ -4020,91 +963,17 @@ snapshots: '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 - '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 - - '@jsquash/avif@1.3.0': - dependencies: - wasm-feature-detect: 1.8.0 - - '@jsquash/jpeg@1.5.0': {} - - '@jsquash/oxipng@2.3.0': - dependencies: - wasm-feature-detect: 1.8.0 - - '@jsquash/png@3.0.1': {} - - '@jsquash/webp@1.4.0': - dependencies: - wasm-feature-detect: 1.8.0 - - '@kwsites/file-exists@1.1.1': - dependencies: - debug: 4.4.0 - transitivePeerDependencies: - - supports-color - - '@kwsites/promise-deferred@1.1.1': {} + '@jridgewell/sourcemap-codec': 1.5.5 '@mozilla/readability@0.6.0': {} - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 - - '@pkgjs/parseargs@0.11.0': - optional: true - - '@pkgr/core@0.1.2': {} - '@popperjs/core@2.11.8': {} - '@protobufjs/aspromise@1.1.2': {} - - '@protobufjs/base64@1.1.2': {} - - '@protobufjs/codegen@2.0.4': {} - - '@protobufjs/eventemitter@1.1.0': {} - - '@protobufjs/fetch@1.1.0': - dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/inquire': 1.1.0 - - '@protobufjs/float@1.0.2': {} - - '@protobufjs/inquire@1.1.0': {} - - '@protobufjs/path@1.1.2': {} - - '@protobufjs/pool@1.1.0': {} - - '@protobufjs/utf8@1.1.0': {} - - '@sindresorhus/is@4.6.0': {} - - '@szmarczak/http-timer@4.0.6': - dependencies: - defer-to-connect: 2.0.1 - - '@tauri-apps/api@2.10.1': {} - '@tauri-apps/cli-darwin-arm64@2.10.0': optional: true @@ -4152,92 +1021,17 @@ snapshots: '@tauri-apps/cli-win32-ia32-msvc': 2.10.0 '@tauri-apps/cli-win32-x64-msvc': 2.10.0 - '@tauri-apps/plugin-fs@2.5.0': - dependencies: - '@tauri-apps/api': 2.10.1 - - '@tauri-apps/plugin-opener@2.5.3': - dependencies: - '@tauri-apps/api': 2.10.1 - - '@thunder04/supermap@3.0.5': {} - - '@tokenizer/token@0.3.0': {} - - '@tootallnate/quickjs-emscripten@0.23.0': {} - - '@types/archiver@6.0.3': - dependencies: - '@types/readdir-glob': 1.1.5 - - '@types/body-parser@1.19.5': - dependencies: - '@types/connect': 3.4.38 - '@types/node': 18.19.86 - - '@types/bytes@3.1.5': {} - - '@types/cacheable-request@6.0.3': - dependencies: - '@types/http-cache-semantics': 4.0.4 - '@types/keyv': 3.1.4 - '@types/node': 18.19.86 - '@types/responselike': 1.0.3 - - '@types/command-exists@1.2.3': {} - - '@types/compression@1.7.5': - dependencies: - '@types/express': 4.17.21 - - '@types/connect@3.4.38': - dependencies: - '@types/node': 18.19.86 - - '@types/cookie-parser@1.4.8(@types/express@4.17.21)': - dependencies: - '@types/express': 4.17.21 - - '@types/cookie-session@2.0.49': - dependencies: - '@types/express': 4.17.21 - '@types/keygrip': 1.0.6 - - '@types/cors@2.8.17': - dependencies: - '@types/node': 18.19.86 - - '@types/deno@2.2.0': {} - '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 - '@types/estree': 1.0.7 + '@types/estree': 1.0.9 '@types/eslint@9.6.1': dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 - '@types/estree@1.0.7': {} - - '@types/express-serve-static-core@4.19.6': - dependencies: - '@types/node': 18.19.86 - '@types/qs': 6.9.18 - '@types/range-parser': 1.2.7 - '@types/send': 0.17.4 - - '@types/express@4.17.21': - dependencies: - '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 4.19.6 - '@types/qs': 6.9.18 - '@types/serve-static': 1.15.7 - - '@types/http-cache-semantics@4.0.4': {} - - '@types/http-errors@2.0.4': {} + '@types/estree@1.0.9': {} '@types/jquery-cropper@1.0.4': dependencies: @@ -4257,70 +1051,16 @@ snapshots: '@types/json-schema@7.0.15': {} - '@types/keygrip@1.0.6': {} - - '@types/keyv@3.1.4': - dependencies: - '@types/node': 18.19.86 - - '@types/lodash@4.17.23': {} - - '@types/long@4.0.2': {} - - '@types/mime-types@2.1.4': {} - - '@types/mime@1.3.5': {} - - '@types/multer@1.4.12': - dependencies: - '@types/express': 4.17.21 - - '@types/node-persist@3.1.8': - dependencies: - '@types/node': 18.19.86 - - '@types/node@16.9.1': {} + '@types/lodash@4.17.24': {} '@types/node@18.19.86': dependencies: undici-types: 5.26.5 - '@types/png-chunk-text@1.0.3': {} - - '@types/png-chunks-extract@1.0.2': {} - - '@types/qs@6.9.18': {} - - '@types/range-parser@1.2.7': {} - - '@types/readdir-glob@1.1.5': - dependencies: - '@types/node': 18.19.86 - - '@types/response-time@2.3.8': - dependencies: - '@types/express': 4.17.21 - '@types/node': 18.19.86 - - '@types/responselike@1.0.3': - dependencies: - '@types/node': 18.19.86 - '@types/select2@4.0.63': dependencies: '@types/jquery': 3.5.33 - '@types/send@0.17.4': - dependencies: - '@types/mime': 1.3.5 - '@types/node': 18.19.86 - - '@types/serve-static@1.15.7': - dependencies: - '@types/http-errors': 2.0.4 - '@types/node': 18.19.86 - '@types/send': 0.17.4 - '@types/sizzle@2.3.9': {} '@types/toastr@2.1.43': @@ -4330,22 +1070,6 @@ snapshots: '@types/trusted-types@2.0.7': optional: true - '@types/write-file-atomic@4.0.3': - dependencies: - '@types/node': 18.19.86 - - '@types/yargs-parser@21.0.3': {} - - '@types/yargs@17.0.33': - dependencies: - '@types/yargs-parser': 21.0.3 - - '@types/yauzl@2.10.3': - dependencies: - '@types/node': 18.19.86 - - '@ungap/structured-clone@1.3.0': {} - '@vue/compiler-core@3.5.33': dependencies: '@babel/parser': 7.29.3 @@ -4476,45 +1200,30 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.99.6)': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.106.2)': dependencies: - webpack: 5.99.6(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack@5.99.6) + webpack: 5.106.2(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack@5.106.2) - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.99.6)': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.106.2)': dependencies: - webpack: 5.99.6(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack@5.99.6) + webpack: 5.106.2(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack@5.106.2) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack@5.99.6)': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack@5.106.2)': dependencies: - webpack: 5.99.6(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack@5.99.6) + webpack: 5.106.2(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack@5.106.2) '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} - '@zeldafan0225/ai_horde@5.2.0': + acorn-import-phases@1.0.4(acorn@8.16.0): dependencies: - '@thunder04/supermap': 3.0.5 + acorn: 8.16.0 - abort-controller@3.0.0: - dependencies: - event-target-shim: 5.0.1 - - accepts@1.3.8: - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - - acorn-jsx@5.3.2(acorn@8.14.1): - dependencies: - acorn: 8.14.1 - - acorn@8.14.1: {} - - agent-base@7.1.3: {} + acorn@8.16.0: {} ajv-formats@2.1.1(ajv@8.17.1): optionalDependencies: @@ -4525,13 +1234,6 @@ snapshots: ajv: 8.17.1 fast-deep-equal: 3.1.3 - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 @@ -4539,773 +1241,83 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ansi-regex@5.0.1: {} - - ansi-regex@6.1.0: {} - - ansi-styles@3.2.1: - dependencies: - color-convert: 1.9.3 - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@6.2.1: {} - - any-base@1.1.0: {} - - app-root-path@3.1.0: {} - - append-field@1.0.0: {} - - archiver-utils@5.0.2: - dependencies: - glob: 10.4.5 - graceful-fs: 4.2.11 - is-stream: 2.0.1 - lazystream: 1.0.1 - lodash: 4.17.21 - normalize-path: 3.0.0 - readable-stream: 4.7.0 - - archiver@7.0.1: - dependencies: - archiver-utils: 5.0.2 - async: 3.2.6 - buffer-crc32: 1.0.0 - readable-stream: 4.7.0 - readdir-glob: 1.1.3 - tar-stream: 3.1.7 - zip-stream: 6.0.1 - - are-docs-informative@0.0.2: {} - - argparse@2.0.1: {} - - array-flatten@1.1.1: {} - - asn1.js@4.10.1: - dependencies: - bn.js: 4.12.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - - assert@2.1.0: - dependencies: - call-bind: 1.0.8 - is-nan: 1.3.2 - object-is: 1.1.6 - object.assign: 4.1.7 - util: 0.12.5 - - ast-types@0.13.4: - dependencies: - tslib: 2.8.1 - - async@3.2.6: {} - - asynckit@0.4.0: {} - - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 - - await-to-js@3.0.0: {} - - axios@0.26.1: - dependencies: - follow-redirects: 1.15.9 - transitivePeerDependencies: - - debug - - axios@1.8.4: - dependencies: - follow-redirects: 1.15.9 - form-data: 4.0.2 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - - b4a@1.6.7: {} - - balanced-match@1.0.2: {} - - bare-events@2.5.4: - optional: true - - base64-js@1.5.1: {} - - basic-ftp@5.0.5: {} - - bing-translate-api@4.0.2: - dependencies: - got: 11.8.6 - - bmp-js@0.1.0: {} - - bmp-ts@1.0.9: {} - - bn.js@4.12.1: {} - - bn.js@5.2.1: {} - - body-parser@1.20.3: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.13.0 - raw-body: 2.5.2 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - boolbase@1.0.0: {} + baseline-browser-mapping@2.10.29: {} bowser@2.14.1: {} - brace-expansion@1.1.11: + browserslist@4.28.2: dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.1: - dependencies: - balanced-match: 1.0.2 - - brorand@1.1.0: {} - - browserify-aes@1.2.0: - dependencies: - buffer-xor: 1.0.3 - cipher-base: 1.0.6 - create-hash: 1.2.0 - evp_bytestokey: 1.0.3 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - browserify-cipher@1.0.1: - dependencies: - browserify-aes: 1.2.0 - browserify-des: 1.0.2 - evp_bytestokey: 1.0.3 - - browserify-des@1.0.2: - dependencies: - cipher-base: 1.0.6 - des.js: 1.1.0 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - browserify-rsa@4.1.1: - dependencies: - bn.js: 5.2.1 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - - browserify-sign@4.2.3: - dependencies: - bn.js: 5.2.1 - browserify-rsa: 4.1.1 - create-hash: 1.2.0 - create-hmac: 1.1.7 - elliptic: 6.6.1 - hash-base: 3.0.5 - inherits: 2.0.4 - parse-asn1: 5.1.7 - readable-stream: 2.3.8 - safe-buffer: 5.2.1 - - browserslist@4.24.4: - dependencies: - caniuse-lite: 1.0.30001714 - electron-to-chromium: 1.5.139 - node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.24.4) - - buffer-crc32@0.2.13: {} - - buffer-crc32@1.0.0: {} - - buffer-equal@0.0.1: {} + baseline-browser-mapping: 2.10.29 + caniuse-lite: 1.0.30001792 + electron-to-chromium: 1.5.354 + node-releases: 2.0.44 + update-browserslist-db: 1.2.3(browserslist@4.28.2) buffer-from@1.1.2: {} - buffer-xor@1.0.3: {} + caniuse-lite@1.0.30001792: {} - buffer@5.7.1: + chevrotain@11.2.0: dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - buffer@6.0.3: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - busboy@1.6.0: - dependencies: - streamsearch: 1.1.0 - - bytes@3.1.2: {} - - cacheable-lookup@5.0.4: {} - - cacheable-request@7.0.4: - dependencies: - clone-response: 1.0.3 - get-stream: 5.2.0 - http-cache-semantics: 4.1.1 - keyv: 4.5.4 - lowercase-keys: 2.0.0 - normalize-url: 6.1.0 - responselike: 2.0.1 - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.8: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - callsites@3.1.0: {} - - caniuse-lite@1.0.30001714: {} - - centra@2.7.0: - dependencies: - follow-redirects: 1.15.9 - transitivePeerDependencies: - - debug - - chalk@2.4.2: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chalk@5.4.1: {} - - cheerio-select@2.1.0: - dependencies: - boolbase: 1.0.0 - css-select: 5.1.0 - css-what: 6.1.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - - cheerio@1.0.0: - dependencies: - cheerio-select: 2.1.0 - dom-serializer: 2.0.0 - domhandler: 5.0.3 - domutils: 3.2.2 - encoding-sniffer: 0.2.0 - htmlparser2: 9.1.0 - parse5: 7.2.1 - parse5-htmlparser2-tree-adapter: 7.1.0 - parse5-parser-stream: 7.1.2 - undici: 6.21.2 - whatwg-mimetype: 4.0.0 - - chevrotain@11.1.1: - dependencies: - '@chevrotain/cst-dts-gen': 11.1.1 - '@chevrotain/gast': 11.1.1 - '@chevrotain/regexp-to-ast': 11.1.1 - '@chevrotain/types': 11.1.1 - '@chevrotain/utils': 11.1.1 + '@chevrotain/cst-dts-gen': 11.2.0 + '@chevrotain/gast': 11.2.0 + '@chevrotain/regexp-to-ast': 11.2.0 + '@chevrotain/types': 11.2.0 + '@chevrotain/utils': 11.2.0 lodash-es: 4.17.23 chrome-trace-event@1.0.4: {} - cipher-base@1.0.6: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - clone-deep@4.0.1: dependencies: is-plain-object: 2.0.4 kind-of: 6.0.3 shallow-clone: 3.0.1 - clone-response@1.0.3: - dependencies: - mimic-response: 1.0.1 - - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.3: {} - - color-name@1.1.4: {} - colorette@2.0.20: {} - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - command-exists@1.2.9: {} - commander@10.0.1: {} commander@2.20.3: {} commander@9.5.0: {} - comment-parser@1.4.1: {} - - compress-commons@6.0.2: - dependencies: - crc-32: 1.2.2 - crc32-stream: 6.0.0 - is-stream: 2.0.1 - normalize-path: 3.0.0 - readable-stream: 4.7.0 - - compressible@2.0.18: - dependencies: - mime-db: 1.54.0 - - compression@1.8.0: - dependencies: - bytes: 3.1.2 - compressible: 2.0.18 - debug: 2.6.9 - negotiator: 0.6.4 - on-headers: 1.0.2 - safe-buffer: 5.2.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - - concat-map@0.0.1: {} - - concat-stream@1.6.2: - dependencies: - buffer-from: 1.1.2 - inherits: 2.0.4 - readable-stream: 2.3.8 - typedarray: 0.0.6 - - content-disposition@0.5.4: - dependencies: - safe-buffer: 5.2.1 - - content-type@1.0.5: {} - - cookie-parser@1.4.7: - dependencies: - cookie: 0.7.2 - cookie-signature: 1.0.6 - - cookie-session@2.1.0: - dependencies: - cookies: 0.9.1 - debug: 3.2.7 - on-headers: 1.0.2 - safe-buffer: 5.2.1 - transitivePeerDependencies: - - supports-color - - cookie-signature@1.0.6: {} - - cookie@0.7.1: {} - - cookie@0.7.2: {} - - cookies@0.9.1: - dependencies: - depd: 2.0.0 - keygrip: 1.1.0 - - core-util-is@1.0.3: {} - - cors@2.8.5: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - - crc-32@0.3.0: {} - - crc-32@1.2.2: {} - - crc32-stream@6.0.0: - dependencies: - crc-32: 1.2.2 - readable-stream: 4.7.0 - - crc@4.3.2(buffer@6.0.3): - optionalDependencies: - buffer: 6.0.3 - - create-ecdh@4.0.4: - dependencies: - bn.js: 4.12.1 - elliptic: 6.6.1 - - create-hash@1.2.0: - dependencies: - cipher-base: 1.0.6 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.11 - - create-hmac@1.1.7: - dependencies: - cipher-base: 1.0.6 - create-hash: 1.2.0 - inherits: 2.0.4 - ripemd160: 2.0.2 - safe-buffer: 5.2.1 - sha.js: 2.4.11 - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - crypto-browserify@3.12.1: - dependencies: - browserify-cipher: 1.0.1 - browserify-sign: 4.2.3 - create-ecdh: 4.0.4 - create-hash: 1.2.0 - create-hmac: 1.1.7 - diffie-hellman: 5.0.3 - hash-base: 3.0.5 - inherits: 2.0.4 - pbkdf2: 3.1.2 - public-encrypt: 4.0.3 - randombytes: 2.1.0 - randomfill: 1.0.4 - - csrf-sync@4.1.0: - dependencies: - http-errors: 2.0.0 - - css-select@5.1.0: - dependencies: - boolbase: 1.0.0 - css-what: 6.1.0 - domhandler: 5.0.3 - domutils: 3.2.2 - nth-check: 2.1.1 - - css-what@6.1.0: {} - csstype@3.2.3: {} - data-uri-to-buffer@4.0.1: {} - - data-uri-to-buffer@6.0.2: {} - - debug@2.6.9: - dependencies: - ms: 2.0.0 - - debug@3.2.7: - dependencies: - ms: 2.1.3 - - debug@4.4.0: - dependencies: - ms: 2.1.3 - - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - - deep-is@0.1.4: {} - - defer-to-connect@2.0.1: {} - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - define-lazy-prop@2.0.0: {} - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - - degenerator@5.0.1: - dependencies: - ast-types: 0.13.4 - escodegen: 2.1.0 - esprima: 4.0.1 - - delayed-stream@1.0.0: {} - - depd@2.0.0: {} - - des.js@1.1.0: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - - destroy@1.2.0: {} - diff-match-patch@1.0.5: {} - diffie-hellman@5.0.3: - dependencies: - bn.js: 4.12.1 - miller-rabin: 4.0.1 - randombytes: 2.1.0 - - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - - dom-serializer@2.0.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - entities: 4.5.0 - - dom-walk@0.1.2: {} - - domelementtype@2.3.0: {} - - domhandler@5.0.3: - dependencies: - domelementtype: 2.3.0 - - dompurify@3.3.1: + dompurify@3.4.3: optionalDependencies: '@types/trusted-types': 2.0.7 - domutils@3.2.2: - dependencies: - dom-serializer: 2.0.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - - dotenv@8.6.0: {} - droll@0.2.1: {} - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 + electron-to-chromium@1.5.354: {} - eastasianwidth@0.2.0: {} - - ee-first@1.1.1: {} - - electron-to-chromium@1.5.139: {} - - elliptic@6.6.1: - dependencies: - bn.js: 4.12.1 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - encodeurl@1.0.2: {} - - encodeurl@2.0.0: {} - - encoding-sniffer@0.2.0: - dependencies: - iconv-lite: 0.6.3 - whatwg-encoding: 3.1.1 - - end-of-stream@1.4.4: - dependencies: - once: 1.4.0 - - enhanced-resolve@5.18.1: + enhanced-resolve@5.21.3: dependencies: graceful-fs: 4.2.11 - tapable: 2.2.1 - - entities@4.5.0: {} + tapable: 2.3.3 entities@7.0.1: {} envinfo@7.14.0: {} - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-module-lexer@1.6.0: {} - es-module-lexer@2.0.0: {} - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - escalade@3.2.0: {} - escape-html@1.0.3: {} - - escape-string-regexp@1.0.5: {} - - escape-string-regexp@4.0.0: {} - - escodegen@2.1.0: - dependencies: - esprima: 4.0.1 - estraverse: 5.3.0 - esutils: 2.0.3 - optionalDependencies: - source-map: 0.6.1 - - eslint-plugin-jsdoc@48.11.0(eslint@8.57.1): - dependencies: - '@es-joy/jsdoccomment': 0.46.0 - are-docs-informative: 0.0.2 - comment-parser: 1.4.1 - debug: 4.4.0 - escape-string-regexp: 4.0.0 - eslint: 8.57.1 - espree: 10.3.0 - esquery: 1.6.0 - parse-imports: 2.2.1 - semver: 7.7.1 - spdx-expression-parse: 4.0.0 - synckit: 0.9.2 - transitivePeerDependencies: - - supports-color - eslint-scope@5.1.1: dependencies: esrecurse: 4.3.0 estraverse: 4.3.0 - eslint-scope@7.2.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.0: {} - - eslint@8.57.1: - dependencies: - '@eslint-community/eslint-utils': 4.6.1(eslint@8.57.1) - '@eslint-community/regexpp': 4.12.1 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.3.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.0 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - - espree@10.3.0: - dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) - eslint-visitor-keys: 4.2.0 - - espree@9.6.1: - dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) - eslint-visitor-keys: 3.4.3 - - esprima@4.0.1: {} - - esquery@1.6.0: - dependencies: - estraverse: 5.3.0 - esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -5316,257 +1328,32 @@ snapshots: estree-walker@2.0.2: {} - esutils@2.0.3: {} - - etag@1.8.1: {} - - event-target-shim@5.0.1: {} - events@3.3.0: {} - evp_bytestokey@1.0.3: - dependencies: - md5.js: 1.3.5 - safe-buffer: 5.2.1 - - exif-parser@0.1.12: {} - - express@4.21.2: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.3 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.7.1 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.3.1 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.3 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.12 - proxy-addr: 2.0.7 - qs: 6.13.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.0 - serve-static: 1.16.2 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - fast-deep-equal@3.1.3: {} - fast-fifo@1.3.2: {} - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - fast-uri@3.0.6: {} fastest-levenshtein@1.0.16: {} - fastq@1.19.1: - dependencies: - reusify: 1.1.0 - - fd-slicer@1.1.0: - dependencies: - pend: 1.2.0 - - fetch-blob@3.2.0: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.3.3 - - file-entry-cache@6.0.1: - dependencies: - flat-cache: 3.2.0 - - file-type@16.5.4: - dependencies: - readable-web-to-node-stream: 3.0.4 - strtok3: 6.3.0 - token-types: 4.2.1 - - finalhandler@1.3.1: - dependencies: - debug: 2.6.9 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color + fflate@0.8.2: {} find-up@4.1.0: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@3.2.0: - dependencies: - flatted: 3.3.3 - keyv: 4.5.4 - rimraf: 3.0.2 - flat@5.0.2: {} - flatbuffers@1.12.0: {} - - flatted@3.3.3: {} - - follow-redirects@1.15.9: {} - - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - form-data@4.0.2: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - mime-types: 2.1.35 - - formdata-polyfill@4.0.10: - dependencies: - fetch-blob: 3.2.0 - - forwarded@0.2.0: {} - - fresh@0.5.2: {} - - fs.realpath@1.0.0: {} - function-bind@1.1.2: {} fuse.js@7.1.0: {} - get-caller-file@2.0.5: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-stream@5.2.0: - dependencies: - pump: 3.0.2 - - get-uri@6.0.4: - dependencies: - basic-ftp: 5.0.5 - data-uri-to-buffer: 6.0.2 - debug: 4.4.0 - transitivePeerDependencies: - - supports-color - - gifwrap@0.10.1: - dependencies: - image-q: 4.0.0 - omggif: 1.0.10 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - glob-to-regexp@0.4.1: {} - glob@10.4.5: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - global@4.4.0: - dependencies: - min-document: 2.19.0 - process: 0.11.10 - - globals@13.24.0: - dependencies: - type-fest: 0.20.2 - - google-translate-api-browser@3.0.1: {} - - google-translate-api-x@10.7.2: {} - - gopd@1.2.0: {} - - got@11.8.6: - dependencies: - '@sindresorhus/is': 4.6.0 - '@szmarczak/http-timer': 4.0.6 - '@types/cacheable-request': 6.0.3 - '@types/responselike': 1.0.3 - cacheable-lookup: 5.0.4 - cacheable-request: 7.0.4 - decompress-response: 6.0.0 - http2-wrapper: 1.0.3 - lowercase-keys: 2.0.0 - p-cancelable: 2.1.1 - responselike: 2.0.1 - - gpt-3-encoder@1.1.4: {} - graceful-fs@4.2.11: {} - graphemer@1.4.0: {} - - guid-typescript@1.0.9: {} - - handlebars@4.7.8: + handlebars@4.7.9: dependencies: minimist: 1.2.8 neo-async: 2.6.2 @@ -5575,291 +1362,52 @@ snapshots: optionalDependencies: uglify-js: 3.19.3 - has-flag@3.0.0: {} - has-flag@4.0.0: {} - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hash-base@3.0.5: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - - hash.js@1.1.7: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - hasown@2.0.2: dependencies: function-bind: 1.1.2 - helmet@7.2.0: {} - highlight.js@11.11.1: {} - hmac-drbg@1.0.1: - dependencies: - hash.js: 1.1.7 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - - html-entities@2.6.0: {} - - htmlparser2@9.1.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - entities: 4.5.0 - - http-cache-semantics@4.1.1: {} - - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.3 - debug: 4.4.0 - transitivePeerDependencies: - - supports-color - - http2-wrapper@1.0.3: - dependencies: - quick-lru: 5.1.1 - resolve-alpn: 1.2.1 - - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.3 - debug: 4.4.0 - transitivePeerDependencies: - - supports-color - - iconv-lite@0.4.24: - dependencies: - safer-buffer: 2.1.2 - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - ieee754@1.2.1: {} - - ignore@5.3.2: {} - - image-q@4.0.0: - dependencies: - '@types/node': 16.9.1 - immediate@3.0.6: {} - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - import-local@3.2.0: dependencies: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 - imurmurhash@0.1.4: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - interpret@3.1.1: {} - ip-address@9.0.5: - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.3 - - ip-matching@2.1.2: {} - - ip-regex@5.0.0: {} - - ipaddr.js@1.9.1: {} - - ipaddr.js@2.2.0: {} - - is-arguments@1.2.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-callable@1.2.7: {} - is-core-module@2.16.1: dependencies: hasown: 2.0.2 - is-docker@2.2.1: {} - - is-docker@3.0.0: {} - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-function@1.0.2: {} - - is-generator-function@1.1.0: - dependencies: - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-nan@1.3.2: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - - is-path-inside@3.0.3: {} - is-plain-object@2.0.4: dependencies: isobject: 3.0.1 - is-regex@1.2.1: - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - is-stream@2.0.1: {} - - is-typed-array@1.1.15: - dependencies: - which-typed-array: 1.1.19 - - is-wsl@2.2.0: - dependencies: - is-docker: 2.2.1 - - isarray@1.0.0: {} - isexe@2.0.0: {} isobject@3.0.1: {} - isomorphic-fetch@3.0.0: - dependencies: - node-fetch: 2.7.0 - whatwg-fetch: 3.6.20 - transitivePeerDependencies: - - encoding - - jackspeak@3.4.3: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - jest-worker@27.5.1: dependencies: '@types/node': 18.19.86 merge-stream: 2.0.0 supports-color: 8.1.1 - jimp@0.22.12: - dependencies: - '@jimp/custom': 0.22.12 - '@jimp/plugins': 0.22.12(@jimp/custom@0.22.12) - '@jimp/types': 0.22.12(@jimp/custom@0.22.12) - regenerator-runtime: 0.13.11 - transitivePeerDependencies: - - debug - - encoding - - jpeg-js@0.4.4: {} - - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - - jsbn@1.1.0: {} - - jsdoc-type-pratt-parser@4.0.0: {} - - json-buffer@3.0.1: {} - - json-colorizer@2.2.2: - dependencies: - chalk: 2.4.2 - lodash.get: 4.4.2 - - json-parse-even-better-errors@2.3.1: {} - - json-schema-traverse@0.4.1: {} + js-sha256@0.11.1: {} json-schema-traverse@1.0.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} - - keygrip@1.1.0: - dependencies: - tsscmp: 1.0.6 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - kind-of@6.0.3: {} - lazystream@1.0.1: - dependencies: - readable-stream: 2.3.8 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - lie@3.1.1: dependencies: immediate: 3.0.6 - load-bmfont@1.4.2: - dependencies: - buffer-equal: 0.0.1 - mime: 1.6.0 - parse-bmfont-ascii: 1.0.6 - parse-bmfont-binary: 1.0.6 - parse-bmfont-xml: 1.1.6 - phin: 3.7.1 - xhr: 2.6.0 - xtend: 4.0.2 - transitivePeerDependencies: - - debug - - loader-runner@4.3.0: {} + loader-runner@4.3.2: {} localforage@1.10.0: dependencies: @@ -5869,513 +1417,68 @@ snapshots: dependencies: p-locate: 4.1.0 - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash-es@4.17.21: {} - lodash-es@4.17.23: {} - lodash.get@4.4.2: {} - - lodash.merge@4.6.2: {} - - lodash@4.17.21: {} - - long@4.0.0: {} - - lowercase-keys@2.0.0: {} - - lru-cache@10.4.3: {} - - lru-cache@7.18.3: {} + lodash@4.18.1: {} magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - math-intrinsics@1.1.0: {} - - md5.js@1.3.5: - dependencies: - hash-base: 3.0.5 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - media-typer@0.3.0: {} - - merge-descriptors@1.0.3: {} - merge-stream@2.0.0: {} - methods@1.1.2: {} - - miller-rabin@4.0.1: - dependencies: - bn.js: 4.12.1 - brorand: 1.1.0 - - mime-db@1.52.0: {} - mime-db@1.54.0: {} - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime@1.6.0: {} - - mime@3.0.0: {} - - mimic-response@1.0.1: {} - - mimic-response@3.1.0: {} - - min-document@2.19.0: - dependencies: - dom-walk: 0.1.2 - - minimalistic-assert@1.0.1: {} - - minimalistic-crypto-utils@1.0.1: {} - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.11 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.1 - - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.1 - minimist@1.2.8: {} - minipass@7.1.2: {} - - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 - moment@2.30.1: {} morphdom@2.7.8: {} - ms@2.0.0: {} - - ms@2.1.3: {} - - multer@1.4.5-lts.2: - dependencies: - append-field: 1.0.0 - busboy: 1.6.0 - concat-stream: 1.6.2 - mkdirp: 0.5.6 - object-assign: 4.1.1 - type-is: 1.6.18 - xtend: 4.0.2 - nanoid@3.3.12: {} - natural-compare@1.4.0: {} - - negotiator@0.6.3: {} - - negotiator@0.6.4: {} - neo-async@2.6.2: {} - netmask@2.0.2: {} - - node-domexception@1.0.0: {} - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - node-fetch@3.3.2: - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - - node-persist@4.0.4: - dependencies: - p-limit: 3.1.0 - - node-releases@2.0.19: {} - - normalize-path@3.0.0: {} - - normalize-url@6.1.0: {} - - nth-check@2.1.1: - dependencies: - boolbase: 1.0.0 - - object-assign@4.1.1: {} - - object-inspect@1.13.4: {} - - object-is@1.1.6: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - - object-keys@1.1.1: {} - - object.assign@4.1.7: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - has-symbols: 1.1.0 - object-keys: 1.1.1 - - omggif@1.0.10: {} - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - on-headers@1.0.2: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onnx-proto@4.0.4: - dependencies: - protobufjs: 6.11.4 - - onnxruntime-common@1.14.0: {} - - onnxruntime-web@1.14.0: - dependencies: - flatbuffers: 1.12.0 - guid-typescript: 1.0.9 - long: 4.0.0 - onnx-proto: 4.0.4 - onnxruntime-common: 1.14.0 - platform: 1.3.6 - - open@8.4.2: - dependencies: - define-lazy-prop: 2.0.0 - is-docker: 2.2.1 - is-wsl: 2.2.0 - - openai@3.3.0: - dependencies: - axios: 0.26.1 - form-data: 4.0.2 - transitivePeerDependencies: - - debug - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - os-browserify@0.3.0: {} - - p-cancelable@2.1.1: {} + node-releases@2.0.44: {} p-limit@2.3.0: dependencies: p-try: 2.2.0 - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - p-locate@4.1.0: dependencies: p-limit: 2.3.0 - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - p-try@2.2.0: {} - pac-proxy-agent@7.2.0: - dependencies: - '@tootallnate/quickjs-emscripten': 0.23.0 - agent-base: 7.1.3 - debug: 4.4.0 - get-uri: 6.0.4 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - pac-resolver: 7.0.1 - socks-proxy-agent: 8.0.5 - transitivePeerDependencies: - - supports-color - - pac-resolver@7.0.1: - dependencies: - degenerator: 5.0.1 - netmask: 2.0.2 - - package-json-from-dist@1.0.1: {} - - pako@1.0.11: {} - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - parse-asn1@5.1.7: - dependencies: - asn1.js: 4.10.1 - browserify-aes: 1.2.0 - evp_bytestokey: 1.0.3 - hash-base: 3.0.5 - pbkdf2: 3.1.2 - safe-buffer: 5.2.1 - - parse-bmfont-ascii@1.0.6: {} - - parse-bmfont-binary@1.0.6: {} - - parse-bmfont-xml@1.1.6: - dependencies: - xml-parse-from-string: 1.0.1 - xml2js: 0.5.0 - - parse-headers@2.0.6: {} - - parse-imports@2.2.1: - dependencies: - es-module-lexer: 1.6.0 - slashes: 3.0.12 - - parse5-htmlparser2-tree-adapter@7.1.0: - dependencies: - domhandler: 5.0.3 - parse5: 7.2.1 - - parse5-parser-stream@7.1.2: - dependencies: - parse5: 7.2.1 - - parse5@7.2.1: - dependencies: - entities: 4.5.0 - - parseurl@1.3.3: {} - - path-browserify@1.0.1: {} - path-exists@4.0.0: {} - path-is-absolute@1.0.1: {} - path-key@3.1.1: {} path-parse@1.0.7: {} - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.2 - - path-to-regexp@0.1.12: {} - - pbkdf2@3.1.2: - dependencies: - create-hash: 1.2.0 - create-hmac: 1.1.7 - ripemd160: 2.0.2 - safe-buffer: 5.2.1 - sha.js: 2.4.11 - - peek-readable@4.1.0: {} - - pend@1.2.0: {} - - phin@3.7.1: - dependencies: - centra: 2.7.0 - transitivePeerDependencies: - - debug - picocolors@1.1.1: {} - pixelmatch@4.0.2: - dependencies: - pngjs: 3.4.0 - pkg-dir@4.2.0: dependencies: find-up: 4.1.0 - platform@1.3.6: {} - - png-chunk-text@1.0.0: {} - - png-chunks-extract@1.0.0: - dependencies: - crc-32: 0.3.0 - - pngjs@3.4.0: {} - - pngjs@6.0.0: {} - - pngjs@7.0.0: {} - - possible-typed-array-names@1.1.0: {} - postcss@8.5.13: dependencies: nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 - prelude-ls@1.2.1: {} - - process-nextick-args@2.0.1: {} - - process@0.11.10: {} - - protobufjs@6.11.4: - dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/base64': 1.1.2 - '@protobufjs/codegen': 2.0.4 - '@protobufjs/eventemitter': 1.1.0 - '@protobufjs/fetch': 1.1.0 - '@protobufjs/float': 1.0.2 - '@protobufjs/inquire': 1.1.0 - '@protobufjs/path': 1.1.2 - '@protobufjs/pool': 1.1.0 - '@protobufjs/utf8': 1.1.0 - '@types/long': 4.0.2 - '@types/node': 18.19.86 - long: 4.0.0 - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - proxy-agent@6.5.0: - dependencies: - agent-base: 7.1.3 - debug: 4.4.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - lru-cache: 7.18.3 - pac-proxy-agent: 7.2.0 - proxy-from-env: 1.1.0 - socks-proxy-agent: 8.0.5 - transitivePeerDependencies: - - supports-color - - proxy-from-env@1.1.0: {} - - public-encrypt@4.0.3: - dependencies: - bn.js: 4.12.1 - browserify-rsa: 4.1.1 - create-hash: 1.2.0 - parse-asn1: 5.1.7 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - - pump@3.0.2: - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - - punycode@2.3.1: {} - - qs@6.13.0: - dependencies: - side-channel: 1.1.0 - - queue-microtask@1.2.3: {} - - quick-lru@5.1.1: {} - - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - - randomfill@1.0.4: - dependencies: - randombytes: 2.1.0 - safe-buffer: 5.2.1 - - range-parser@1.2.1: {} - - rate-limiter-flexible@5.0.5: {} - - raw-body@2.5.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - - readable-stream@4.7.0: - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - - readable-web-to-node-stream@3.0.4: - dependencies: - readable-stream: 4.7.0 - - readdir-glob@1.1.3: - dependencies: - minimatch: 5.1.6 - rechoir@0.8.0: dependencies: resolve: 1.22.10 - regenerator-runtime@0.13.11: {} - - require-directory@2.1.1: {} - require-from-string@2.0.2: {} - resolve-alpn@1.2.1: {} - resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 - resolve-from@4.0.0: {} - resolve-from@5.0.0: {} resolve@1.22.10: @@ -6384,49 +1487,7 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - response-time@2.3.3: - dependencies: - depd: 2.0.0 - on-headers: 1.0.2 - - responselike@2.0.1: - dependencies: - lowercase-keys: 2.0.0 - - reusify@1.1.0: {} - - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - - ripemd160@2.0.2: - dependencies: - hash-base: 3.0.5 - inherits: 2.0.4 - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - safe-buffer@5.1.2: {} - - safe-buffer@5.2.1: {} - - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 - - safer-buffer@2.1.2: {} - - sanitize-filename@1.6.3: - dependencies: - truncate-utf8-bytes: 1.0.2 - - sax@1.4.1: {} - - schema-utils@4.3.0: + schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 ajv: 8.17.1 @@ -6435,55 +1496,6 @@ snapshots: seedrandom@3.0.5: {} - semver@7.7.1: {} - - send@0.19.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 - - serve-static@1.16.2: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.0 - transitivePeerDependencies: - - supports-color - - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - setprototypeof@1.2.0: {} - - sha.js@2.4.11: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - shallow-clone@3.0.1: dependencies: kind-of: 6.0.3 @@ -6498,72 +1510,6 @@ snapshots: dependencies: commander: 9.5.0 - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - signal-exit@4.1.0: {} - - sillytavern-transformers@2.14.6: - dependencies: - '@huggingface/jinja': 0.1.3 - jimp: 0.22.12 - onnxruntime-web: 1.14.0 - transitivePeerDependencies: - - debug - - encoding - - simple-git@3.27.0: - dependencies: - '@kwsites/file-exists': 1.1.1 - '@kwsites/promise-deferred': 1.1.1 - debug: 4.4.0 - transitivePeerDependencies: - - supports-color - - slashes@3.0.12: {} - - slidetoggle@4.0.0: {} - - smart-buffer@4.2.0: {} - - socks-proxy-agent@8.0.5: - dependencies: - agent-base: 7.1.3 - debug: 4.4.0 - socks: 2.8.4 - transitivePeerDependencies: - - supports-color - - socks@2.8.4: - dependencies: - ip-address: 9.0.5 - smart-buffer: 4.2.0 - source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -6573,153 +1519,29 @@ snapshots: source-map@0.6.1: {} - spdx-exceptions@2.5.0: {} - - spdx-expression-parse@4.0.0: - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.21 - - spdx-license-ids@3.0.21: {} - - sprintf-js@1.1.3: {} - - statuses@2.0.1: {} - - stream-browserify@3.0.0: - dependencies: - inherits: 2.0.4 - readable-stream: 3.6.2 - - streamsearch@1.1.0: {} - - streamx@2.22.0: - dependencies: - fast-fifo: 1.3.2 - text-decoder: 1.2.3 - optionalDependencies: - bare-events: 2.5.4 - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.1.0: - dependencies: - ansi-regex: 6.1.0 - - strip-json-comments@3.1.1: {} - - strtok3@6.3.0: - dependencies: - '@tokenizer/token': 0.3.0 - peek-readable: 4.1.0 - - supports-color@5.5.0: - dependencies: - has-flag: 3.0.0 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - supports-color@8.1.1: dependencies: has-flag: 4.0.0 supports-preserve-symlinks-flag@1.0.0: {} - synckit@0.9.2: - dependencies: - '@pkgr/core': 0.1.2 - tslib: 2.8.1 + tapable@2.3.3: {} - tapable@2.2.1: {} - - tar-stream@3.1.7: - dependencies: - b4a: 1.6.7 - fast-fifo: 1.3.2 - streamx: 2.22.0 - - terser-webpack-plugin@5.3.14(webpack@5.99.6): + terser-webpack-plugin@5.6.0(webpack@5.106.2): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 - schema-utils: 4.3.0 - serialize-javascript: 6.0.2 + schema-utils: 4.3.3 terser: 5.39.0 - webpack: 5.99.6(webpack-cli@5.1.4) + webpack: 5.106.2(webpack-cli@5.1.4) terser@5.39.0: dependencies: '@jridgewell/source-map': 0.3.6 - acorn: 8.14.1 + acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 - text-decoder@1.2.3: - dependencies: - b4a: 1.6.7 - - text-table@0.2.0: {} - - tiktoken@1.0.22: {} - - timm@1.7.1: {} - - tinycolor2@1.6.0: {} - - toidentifier@1.0.1: {} - - token-types@4.2.1: - dependencies: - '@tokenizer/token': 0.3.0 - ieee754: 1.2.1 - - tr46@0.0.3: {} - - truncate-utf8-bytes@1.0.2: - dependencies: - utf8-byte-length: 1.0.5 - - tslib@2.8.1: {} - - tsscmp@1.0.6: {} - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-fest@0.20.2: {} - - type-is@1.6.18: - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - - typedarray@0.0.6: {} - typescript@5.9.3: {} uglify-js@3.19.3: @@ -6727,57 +1549,12 @@ snapshots: undici-types@5.26.5: {} - undici@6.21.2: {} - - unpipe@1.0.0: {} - - update-browserslist-db@1.1.3(browserslist@4.24.4): + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: - browserslist: 4.24.4 + browserslist: 4.28.2 escalade: 3.2.0 picocolors: 1.1.1 - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - url-join@5.0.0: {} - - utf8-byte-length@1.0.5: {} - - utif2@4.1.0: - dependencies: - pako: 1.0.11 - - util-deprecate@1.0.2: {} - - util@0.12.5: - dependencies: - inherits: 2.0.4 - is-arguments: 1.2.0 - is-generator-function: 1.1.0 - is-typed-array: 1.1.15 - which-typed-array: 1.1.19 - - utils-merge@1.0.1: {} - - uuid@9.0.1: {} - - vary@1.1.2: {} - - vectra@0.2.2: - dependencies: - axios: 1.8.4 - cheerio: 1.0.0 - dotenv: 8.6.0 - gpt-3-encoder: 1.1.4 - json-colorizer: 2.2.2 - openai: 3.3.0 - uuid: 9.0.1 - yargs: 17.7.2 - transitivePeerDependencies: - - debug - vue@3.5.33(typescript@5.9.3): dependencies: '@vue/compiler-dom': 3.5.33 @@ -6788,25 +1565,17 @@ snapshots: optionalDependencies: typescript: 5.9.3 - wasm-feature-detect@1.8.0: {} - - watchpack@2.4.2: + watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - wavefile@11.0.0: {} - - web-streams-polyfill@3.3.3: {} - - webidl-conversions@3.0.1: {} - - webpack-cli@5.1.4(webpack@5.99.6): + webpack-cli@5.1.4(webpack@5.106.2): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.99.6) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.99.6) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack@5.99.6) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.106.2) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.106.2) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack@5.106.2) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.6 @@ -6815,7 +1584,7 @@ snapshots: import-local: 3.2.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.99.6(webpack-cli@5.1.4) + webpack: 5.106.2(webpack-cli@5.1.4) webpack-merge: 5.10.0 webpack-merge@5.10.0: @@ -6824,139 +1593,54 @@ snapshots: flat: 5.0.2 wildcard: 2.0.1 - webpack-sources@3.2.3: {} + webpack-sources@3.4.1: {} - webpack@5.99.6(webpack-cli@5.1.4): + webpack@5.106.2(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.7 + '@types/estree': 1.0.9 + '@types/json-schema': 7.0.15 '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.14.1 - browserslist: 4.24.4 + acorn: 8.16.0 + acorn-import-phases: 1.0.4(acorn@8.16.0) + browserslist: 4.28.2 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.1 - es-module-lexer: 1.6.0 + enhanced-resolve: 5.21.3 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 - mime-types: 2.1.35 + loader-runner: 4.3.2 + mime-db: 1.54.0 neo-async: 2.6.2 - schema-utils: 4.3.0 - tapable: 2.2.1 - terser-webpack-plugin: 5.3.14(webpack@5.99.6) - watchpack: 2.4.2 - webpack-sources: 3.2.3 + schema-utils: 4.3.3 + tapable: 2.3.3 + terser-webpack-plugin: 5.6.0(webpack@5.106.2) + watchpack: 2.5.1 + webpack-sources: 3.4.1 optionalDependencies: - webpack-cli: 5.1.4(webpack@5.99.6) + webpack-cli: 5.1.4(webpack@5.106.2) transitivePeerDependencies: + - '@minify-html/node' - '@swc/core' + - '@swc/css' + - '@swc/html' + - clean-css + - cssnano + - csso - esbuild + - html-minifier-terser + - lightningcss + - postcss - uglify-js - whatwg-encoding@3.1.1: - dependencies: - iconv-lite: 0.6.3 - - whatwg-fetch@3.6.20: {} - - whatwg-mimetype@4.0.0: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - which-typed-array@1.1.19: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - which@2.0.2: dependencies: isexe: 2.0.0 wildcard@2.0.1: {} - word-wrap@1.2.5: {} - wordwrap@1.0.0: {} - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 - - wrappy@1.0.2: {} - - write-file-atomic@5.0.1: - dependencies: - imurmurhash: 0.1.4 - signal-exit: 4.1.0 - - ws@8.18.1: {} - - xhr@2.6.0: - dependencies: - global: 4.4.0 - is-function: 1.0.2 - parse-headers: 2.0.6 - xtend: 4.0.2 - - xml-parse-from-string@1.0.1: {} - - xml2js@0.5.0: - dependencies: - sax: 1.4.1 - xmlbuilder: 11.0.1 - - xmlbuilder@11.0.1: {} - - xtend@4.0.2: {} - - y18n@5.0.8: {} - - yaml@2.8.2: {} - - yargs-parser@21.1.1: {} - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - - yauzl@2.10.0: - dependencies: - buffer-crc32: 0.2.13 - fd-slicer: 1.1.0 - - yocto-queue@0.1.0: {} - - zip-stream@6.0.1: - dependencies: - archiver-utils: 5.0.2 - compress-commons: 6.0.2 - readable-stream: 4.7.0 - - zod@3.24.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..d6dd0641 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +onlyBuiltDependencies: + - protobufjs diff --git a/src-tauri/src/presentation/commands/bridge.rs b/src-tauri/src/presentation/commands/bridge.rs index 9ce6ec40..cdc4fefd 100644 --- a/src-tauri/src/presentation/commands/bridge.rs +++ b/src-tauri/src/presentation/commands/bridge.rs @@ -9,7 +9,7 @@ use crate::presentation::errors::CommandError; #[cfg(any(dev, debug_assertions))] use crate::presentation::web_resources::dev_resource_dispatch::dispatch_dev_web_resource_request; -const SILLYTAVERN_COMPAT_VERSION: &str = "1.16.0"; +const SILLYTAVERN_COMPAT_VERSION: &str = "1.18.0"; const BUILD_GIT_REVISION: &str = env!("TAURITAVERN_GIT_REVISION"); const BUILD_GIT_BRANCH: &str = env!("TAURITAVERN_GIT_BRANCH"); diff --git a/src/compat-version.js b/src/compat-version.js index 097e6705..cc213c44 100644 --- a/src/compat-version.js +++ b/src/compat-version.js @@ -1 +1 @@ -export const SILLYTAVERN_COMPAT_VERSION = '1.16.0'; +export const SILLYTAVERN_COMPAT_VERSION = '1.18.0'; diff --git a/src/css/!USER-CSS-README.md b/src/css/!USER-CSS-README.md new file mode 100644 index 00000000..2fddf864 --- /dev/null +++ b/src/css/!USER-CSS-README.md @@ -0,0 +1,7 @@ +# Looking for user.css? + +user.css is now located under your data root directory in the "_css" folder. + +Example for the default data root: + +/data/_css/user.css diff --git a/src/css/loader.css b/src/css/loader.css index 3bb3006a..93ee05d2 100644 --- a/src/css/loader.css +++ b/src/css/loader.css @@ -29,3 +29,60 @@ align-items: center; justify-content: center; } + +/* Action loader toast styles */ +.action-loader-toast { + display: flex; + align-items: center; + gap: 10px; + width: 100%; +} + +.action-loader-message { + flex: 1; +} + +.action-loader-stop { + cursor: pointer; + font-size: 1.2em; + opacity: 0.8; + transition: opacity 0.15s ease, color 0.15s ease; +} + +.action-loader-stop:hover { + opacity: 1; + color: color-mix(in srgb, currentColor 40%, #e74c3c 60%); +} + +/* Splash screen styles for branded loading */ +#loader.splash-screen { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 4rem; + width: 100%; + height: 100%; + transition: all var(--animation-duration-2x) ease-out; +} + +#loader.splash-screen #load-spinner { + position: static; + top: unset; + left: unset; +} + +.splash-logo { + /* max original px, or 50% on mobile */ + width: min(150px, 50%); + height: auto; + filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3)); +} + +.splash-message { + margin: 0; + font-size: 1.25rem; + font-weight: 500; + opacity: 0.9; + letter-spacing: 0.02em; +} diff --git a/src/css/streaming-display.css b/src/css/streaming-display.css new file mode 100644 index 00000000..e3f5148f --- /dev/null +++ b/src/css/streaming-display.css @@ -0,0 +1,236 @@ +/* ───────────────────────────────────────────────────────────────────────────── + Streaming Display — floating toast panel for live LLM generation output. + Shows reasoning (thinking) and content as they stream in. + Used by extensions that leverage ConnectionManagerRequestService streaming. + ───────────────────────────────────────────────────────────────────────────── */ + +.streaming-display { + position: fixed; + bottom: max(calc(var(--bottomFormBlockSize) + 5px), 20px); + right: 20px; + width: min(550px, calc(100vw - 40px)); + max-height: 70vh; + background: var(--SmartThemeBlurTintColor); + border: 1px solid var(--SmartThemeBorderColor); + border-radius: 10px; + padding: 14px; + z-index: 9000; + display: flex; + flex-direction: column; + gap: 10px; + opacity: 0; + transform: translateY(20px); + transition: opacity var(--animation-duration, 125ms) ease, transform var(--animation-duration, 125ms) ease; + overflow: hidden; + box-shadow: 0 4px 24px rgba(0, 0, 0, 0.25); + backdrop-filter: blur(12px); +} + +.streaming-display-visible { + opacity: 1; + transform: translateY(0); +} + +/* Header label with animated activity indicator */ +.streaming-display-label { + font-weight: 600; + font-size: 0.95em; + color: var(--SmartThemeBodyColor); + display: flex; + align-items: center; + gap: 8px; + user-select: none; +} + +/* LED status indicator - pulsing while streaming */ +.streaming-display-led { + display: inline-block; + width: 8px; + height: 8px; + border-radius: 50%; + background: rgb(225, 138, 36); + animation: streaming-display-pulse 1.5s ease-in-out infinite; + flex-shrink: 0; +} + +/* Completed state: solid green LED */ +.streaming-display-complete .streaming-display-led { + background: #4caf50; + animation: none; + opacity: 1; + box-shadow: 0 0 8px rgba(76, 175, 80, 0.6); +} + +/* Stopped state: solid red LED */ +.streaming-display-stopped .streaming-display-led { + background: #f44336; + animation: none; + opacity: 1; + box-shadow: 0 0 8px rgba(244, 67, 54, 0.6); +} + +@keyframes streaming-display-pulse { + 0%, 100% { opacity: 0.4; transform: scale(0.9); } + 50% { opacity: 1; transform: scale(1.1); } +} + +/* Label text takes available space */ +.streaming-display-label-text { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* Window control buttons container */ +.streaming-display-controls { + display: flex; + align-items: center; + gap: 4px; + margin-left: auto; + flex-shrink: 0; +} + +/* Window control buttons */ +.streaming-display-btn { + width: 22px; + height: 22px; + border: none; + border-radius: 4px; + background: transparent; + color: var(--SmartThemeBodyColor); + font-size: 14px; + line-height: 1; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + opacity: 0.6; + transition: opacity 0.15s ease, background-color 0.15s ease; +} + +.streaming-display-btn:hover { + opacity: 1; + background-color: rgba(255, 255, 255, 0.1); +} + +.streaming-display-btn-close:hover { + background-color: rgba(244, 67, 54, 0.2); +} + +.streaming-display-btn-stop { + font-size: 10px; +} + +.streaming-display-btn-stop:hover { + background-color: rgba(244, 150, 36, 0.2); + color: rgb(225, 138, 36); +} + +/* Content container - collapsible for minimize */ +.streaming-display-content { + display: flex; + flex-direction: column; + gap: 10px; + overflow: hidden; + transition: max-height var(--animation-duration, 125ms) ease, opacity var(--animation-duration, 125ms) ease; +} + +/* Minimized state - hide content sections */ +.streaming-display-minimized .streaming-display-content { + max-height: 0; + opacity: 0; +} + +.streaming-display-minimized { + gap: 0; +} + +/* Model/API icon in the label */ +.streaming-display-icon { + width: 1.1em; + height: 1.1em; + flex-shrink: 0; +} + +/* Minimized state adjustments */ +.streaming-display-minimized.streaming-display { + padding: 10px 14px; +} + +/* Reasoning (thinking) section */ +.streaming-display-reasoning { + background: color-mix(in srgb, var(--SmartThemeBodyColor) 5%, transparent); + border-radius: 6px; + padding: 8px 10px; + border-left: 3px solid color-mix(in srgb, var(--SmartThemeBodyColor) 25%, transparent); +} + +.streaming-display-reasoning-label { + font-size: 0.8em; + font-weight: 600; + opacity: 0.5; + margin-bottom: 4px; + letter-spacing: 0.03em; + text-transform: uppercase; +} + +.streaming-display-reasoning-content { + font-size: 0.82em; + opacity: 0.65; + max-height: 25vh; + overflow-y: auto; + word-break: break-word; + line-height: 1.45; + scrollbar-width: thin; +} + +.streaming-display-reasoning-content p { + margin: 0.3em 0; +} + +.streaming-display-reasoning-content p:first-child { + margin-top: 0; +} + +.streaming-display-reasoning-content p:last-child { + margin-bottom: 0; +} + +/* Main content section */ +.streaming-display-text { + border-top: 1px solid color-mix(in srgb, var(--SmartThemeBorderColor) 50%, transparent); + padding-top: 8px; + min-height: 1.5em; +} + +.streaming-display-text-content { + font-size: 0.9em; + color: var(--SmartThemeBodyColor); + max-height: 40vh; + overflow-y: auto; + word-break: break-word; + line-height: 1.5; + scrollbar-width: thin; +} + +.streaming-display-text-content p { + margin: 0.4em 0; +} + +.streaming-display-text-content p:first-child { + margin-top: 0; +} + +.streaming-display-text-content p:last-child { + margin-bottom: 0; +} + +/* Strip auto-added quotes from tags, as message formatting adds them */ +.streaming-display-reasoning-content q:before, +.streaming-display-reasoning-content q:after, +.streaming-display-text-content q:before, +.streaming-display-text-content q:after { + content: ''; +} diff --git a/src/css/toggle-dependent.css b/src/css/toggle-dependent.css index fad4c684..731f57cc 100644 --- a/src/css/toggle-dependent.css +++ b/src/css/toggle-dependent.css @@ -565,6 +565,16 @@ label[for="bind_preset_to_connection"]:has(input:checked) { display: none; } +#openai_settings:has(#openai_function_calling:not(:checked)) #tool_call_recurse_limit_block { + display: none; +} + #adaptive_p_block:has([data-tg-samplers="adaptive_target"][style*="display: none"]):has([data-tg-samplers="adaptive_decay"][style*="display: none"]) { display: none; } + +#openrouter_provider_warning_text, +#openrouter_provider_warning_chat { + color: var(--warning); + margin-left: 5px; +} diff --git a/src/css/welcome.css b/src/css/welcome.css index 9f292ed5..b5e43cd6 100644 --- a/src/css/welcome.css +++ b/src/css/welcome.css @@ -17,6 +17,7 @@ .welcomePanel.recentHidden .welcomeRecent, .welcomePanel.recentHidden .recentChatsTitle, .welcomePanel.recentHidden .hideRecentChats, +.welcomePanel.recentHidden .recentChatsSettings, .welcomePanel:not(.recentHidden) .showRecentChats { display: none; } diff --git a/src/global.d.ts b/src/global.d.ts index 78b15f48..b4d321aa 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1,6 +1,6 @@ import libs from './lib'; import getContext from './scripts/st-context'; -import { power_user } from './scripts/power-user'; +import { power_user, getThemeObject } from './scripts/power-user'; import { QuickReplyApi } from './scripts/extensions/quick-reply/api/QuickReplyApi'; import { oai_settings } from './scripts/openai'; import { textgenerationwebui_settings } from './scripts/textgen-settings'; @@ -21,6 +21,7 @@ declare global { type MessageTimestamp = string | number | Date; type Character = import('./scripts/char-data').v1CharData; type ChatMessageExtra = BaseMessageExtra & Partial & Record; + type Theme = ReturnType; interface Group { id: string; @@ -138,6 +139,8 @@ declare global { interface ImageGenerationAttachmentProps { generation_type?: number; negative?: string; + width?: number; + height?: number; } interface ImageCaptionAttachmentProps { diff --git a/src/img/logo.svg b/src/img/logo.svg new file mode 100644 index 00000000..8798833e --- /dev/null +++ b/src/img/logo.svg @@ -0,0 +1,2 @@ + + diff --git a/src/img/minimax.svg b/src/img/minimax.svg new file mode 100644 index 00000000..1d32449a --- /dev/null +++ b/src/img/minimax.svg @@ -0,0 +1 @@ +Minimax \ No newline at end of file diff --git a/src/img/workers_ai.svg b/src/img/workers_ai.svg new file mode 100644 index 00000000..14f73da0 --- /dev/null +++ b/src/img/workers_ai.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/index.html b/src/index.html index 794c7fdc..fc3f8d69 100644 --- a/src/index.html +++ b/src/index.html @@ -698,7 +698,7 @@ -
+
Temperature
@@ -711,7 +711,7 @@
-
+
Frequency Penalty
@@ -724,7 +724,7 @@
-
+
Presence Penalty
@@ -737,7 +737,7 @@
-
+
Top K
@@ -750,7 +750,7 @@
-
+
Top P
@@ -763,7 +763,7 @@
-
+
Repetition Penalty
@@ -987,7 +987,7 @@
-
+
Seed
@@ -1270,8 +1270,8 @@ Top K
- - + +
@@ -1401,7 +1401,7 @@
- -
+
-
+
+
+
+ Tool Call Recurse Limit +
+
+
+
+ +
+
+ +
+
+
-
+
+
+
+ + +
+
+
+ + Sends reasoning from preceding assistant turns with tool-call requests to maintain interleaved thinking context. + +
+ +
+
-
+
-
+
@@ -2437,10 +2483,13 @@
-

Model Providers

+

+ Model Providers + +

-
+
+

@@ -4333,7 +4428,7 @@ First User Prefix

-
+
Last User Prefix
@@ -4743,7 +4838,7 @@ or + + + +

@@ -5951,8 +6077,8 @@ - - + + @@ -6103,8 +6229,14 @@
- +
+
@@ -6584,10 +6716,34 @@
+
+
+
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+
+ + New Folder +
+
@@ -6638,7 +6794,7 @@
-
+
@@ -7302,6 +7458,7 @@
+
diff --git a/src/lib-bundle-core.js b/src/lib-bundle-core.js index d1cacb87..6814edbc 100644 --- a/src/lib-bundle-core.js +++ b/src/lib-bundle-core.js @@ -20,6 +20,10 @@ import * as Popper from '@popperjs/core'; import droll from 'droll'; import morphdom from 'morphdom'; import * as chevrotain from 'chevrotain'; +import { gzipSync, gzip } from 'fflate'; +import jsSha256Module from 'js-sha256'; + +const jsSha256 = jsSha256Module.sha256 ?? jsSha256Module; const libBundle = { lodash, @@ -38,6 +42,9 @@ const libBundle = { droll, morphdom, chevrotain, + gzipSync, + gzip, + sha256: jsSha256, initialized: true, }; @@ -58,7 +65,9 @@ export { droll, morphdom, chevrotain, + gzipSync, + gzip, + jsSha256 as sha256, }; export default libBundle; - diff --git a/src/lib.js b/src/lib.js index cb9b3540..cc899c1b 100644 --- a/src/lib.js +++ b/src/lib.js @@ -24,6 +24,9 @@ import libCoreBundle, { droll, morphdom, chevrotain, + gzipSync, + gzip, + sha256, } from './dist/lib.core.bundle.js'; let optionalBundlePromise = null; @@ -177,6 +180,9 @@ export { droll, morphdom, chevrotain, + gzipSync, + gzip, + sha256, }; export default libCoreBundle; diff --git a/src/locales/ar-sa.json b/src/locales/ar-sa.json index 3ef56775..31c28830 100644 --- a/src/locales/ar-sa.json +++ b/src/locales/ar-sa.json @@ -337,6 +337,8 @@ "koboldcpp API key (optional)": "مفتاح koboldcpp API (اختياري)", "Example: http://127.0.0.1:5001": "مثال: http://127.0.0.1:5001", "Authorize": "تفويض", + "OpenRouter API key already exists": "مفتاح API OpenRouter موجود بالفعل", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "هل تريد حقاً إنشاء مفتاح OpenRouter جديد؟ لن يتم حذف مفتاحك الموجود.", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "احصل على رمز واجهة برمجة التطبيقات الخاص بك لموزع الاتصالات باستخدام تدفق OAuth. سيتم توجيهك إلى openrouter.ai", "Bypass status check": "تجاوز فحص الحالة", "Chat Completion Source": "مصدر استكمال الدردشة", @@ -1438,5 +1440,19 @@ "Still have questions?": "هل ما زالت لديك اسئلة؟", "Join the SillyTavern Discord": "انضم إلى ديسكورد SillyTavern", "Post a GitHub issue": "نشر مشكلة على GitHub", - "Contact the developers": "الاتصال بالمطورين" + "Contact the developers": "الاتصال بالمطورين", + "Interleaved Thinking": "التفكير المتداخل", + "Since Last User Message": "منذ آخر رسالة من المستخدم", + "Active Tool Chain": "سلسلة الأدوات النشطة", + "openrouter_interleaved_thinking_hint": "يرسل الاستدلال من رسائل المساعد السابقة مع طلبات استدعاء الأدوات للحفاظ على سياق التفكير المتداخل.", + "SillyTavern Logo": "شعار SillyTavern", + "Initializing…": "جارٍ التهيئة…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "الاسم غير مقبول، لأنه نفسه كما كان من قبل (تجاهل حالة الأحرف والنبرات).", + "Rename Chat": "إعادة تسمية المحادثة", + "Renaming chat…": "جارٍ إعادة تسمية المحادثة…", + "Delete Chat": "حذف المحادثة", + "Deleting chat…": "جارٍ حذف المحادثة…", + "Loading chat…": "جارٍ تحميل المحادثة…", + "Bulk Delete": "حذف جماعي", + "Deleting ${0} character(s)…": "جارٍ حذف ${0} شخصية (شخصيات)…" } diff --git a/src/locales/de-de.json b/src/locales/de-de.json index cf942a10..eede60a6 100644 --- a/src/locales/de-de.json +++ b/src/locales/de-de.json @@ -337,6 +337,8 @@ "koboldcpp API key (optional)": "koboldcpp API-Schlüssel (optional)", "Example: http://127.0.0.1:5001": "Beispiel: http://127.0.0.1:5001", "Authorize": "Autorisieren", + "OpenRouter API key already exists": "OpenRouter API-Schlüssel existiert bereits", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "Möchten Sie wirklich einen neuen OpenRouter API-Schlüssel erstellen? Ihr vorhandener Schlüssel wird nicht gelöscht.", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Hole dein OpenRouter-API-Token mit OAuth-Fluss. Du wirst zu openrouter.ai weitergeleitet", "Bypass status check": "Umgehe Statusüberprüfung", "Chat Completion Source": "Quelle für Chat-Vervollständigung", @@ -1438,5 +1440,19 @@ "Still have questions?": "Hast du immer noch Fragen?", "Join the SillyTavern Discord": "Trete dem SillyTavern Discord bei", "Post a GitHub issue": "Veröffentliche ein GitHub-Problem", - "Contact the developers": "Kontaktiere die Entwickler" + "Contact the developers": "Kontaktiere die Entwickler", + "Interleaved Thinking": "Verschränktes Denken", + "Since Last User Message": "Seit letzter Nutzernachricht", + "Active Tool Chain": "Aktive Tool-Kette", + "openrouter_interleaved_thinking_hint": "Sendet Begründungen aus vorherigen Assistentennachrichten mit Tool-Aufrufen, um den Kontext für verschränktes Denken zu erhalten.", + "SillyTavern Logo": "SillyTavern-Logo", + "Initializing…": "Initialisierung…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "Name nicht akzeptiert, da er derselbe wie zuvor ist (Groß-/Kleinschreibung und Akzente ignoriert).", + "Rename Chat": "Chat umbenennen", + "Renaming chat…": "Chat wird umbenannt…", + "Delete Chat": "Chat löschen", + "Deleting chat…": "Chat wird gelöscht…", + "Loading chat…": "Chat wird geladen…", + "Bulk Delete": "Massenlöschung", + "Deleting ${0} character(s)…": "${0} Charakter(e) werden gelöscht…" } diff --git a/src/locales/es-es.json b/src/locales/es-es.json index b38dc536..f3f099e3 100644 --- a/src/locales/es-es.json +++ b/src/locales/es-es.json @@ -337,6 +337,8 @@ "koboldcpp API key (optional)": "Clave API de koboldcpp (opcional)", "Example: http://127.0.0.1:5001": "Ejemplo: http://127.0.0.1:5001", "Authorize": "Autorizar", + "OpenRouter API key already exists": "La clave de API de OpenRouter ya existe", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "¿Realmente deseas crear una nueva clave de API de OpenRouter? Tu clave existente no será eliminada.", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Obtenga su token de API de OpenRouter utilizando el flujo OAuth. Será redirigido a openrouter.ai", "Bypass status check": "Saltar la verificación del estado", "Chat Completion Source": "Fuente de Completado de Chat", @@ -1545,5 +1547,19 @@ "Toggles sharing world tint with character sprites (This will override Character Tint)": "Alterna el tinte mundial compartido con los sprites de personajes (esto anulará el tinte de personajes)", "Sets the expression of the user sprite": "Establece la expresión del sprite de usuario", "Sets the user sprite set to use for the user sprite": "Establece el conjunto de sprites de usuario para usar en el sprite de usuario", - "Toggles the user sprite on the VN UI": "Alterna el sprite de usuario en la interfaz VN" + "Toggles the user sprite on the VN UI": "Alterna el sprite de usuario en la interfaz VN", + "Interleaved Thinking": "Razonamiento intercalado", + "Since Last User Message": "Desde el último mensaje del usuario", + "Active Tool Chain": "Cadena de herramientas activa", + "openrouter_interleaved_thinking_hint": "Envía razonamiento de turnos anteriores del asistente junto con solicitudes de herramientas para mantener el contexto del razonamiento intercalado.", + "SillyTavern Logo": "Logo de SillyTavern", + "Initializing…": "Inicializando…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "Nombre no aceptado, ya que es el mismo que antes (ignorando mayúsculas y acentos).", + "Rename Chat": "Renombrar chat", + "Renaming chat…": "Renombrando chat…", + "Delete Chat": "Eliminar chat", + "Deleting chat…": "Eliminando chat…", + "Loading chat…": "Cargando chat…", + "Bulk Delete": "Eliminación masiva", + "Deleting ${0} character(s)…": "Eliminando ${0} personaje(s)…" } diff --git a/src/locales/fr-fr.json b/src/locales/fr-fr.json index a1f564fa..fb4d709a 100644 --- a/src/locales/fr-fr.json +++ b/src/locales/fr-fr.json @@ -320,6 +320,8 @@ "koboldcpp API key (optional)": "Clé API koboldcpp (facultatif)", "Example: http://127.0.0.1:5001": "Exemple : http://127.0.0.1:5001", "Authorize": "Autoriser", + "OpenRouter API key already exists": "La clé API OpenRouter existe déjà", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "Voulez-vous vraiment créer une nouvelle clé OpenRouter ? Votre clé existante ne sera pas supprimée.", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Obtenez votre jeton API OpenRouter en utilisant le flux OAuth. Vous serez redirigé vers openrouter.ai", "Bypass status check": "Contourner la vérification de l'état", "Chat Completion Source": "Source de complétion de chat", @@ -1516,10 +1518,10 @@ "Contain": "Contenir", "Stretch": "Étirer", "Center": "Centrer", - "Persona Lore Alt+Click to open the lorebook": "Lore de persona\nAlt+Click pour ouvrir le lorebook", + "persona_lore_button_title": "Lore de persona\n\nCliquer pour charger\nMajuscule/Alt-clic ou appui long pour ouvrir la fenêtre contextuelle « Lien vers le Lorebook de persona ».", "None (disabled)": "Aucun (désactivé)", - "world_button_title": "Lore de personnage\n\nCliquer pour charger\nMajuscule-clic pour ouvrir la fenêtre contextuelle « Lien vers le Wold Info ».", - "Chat Lore Alt+Click to open the lorebook": "Lore du chat\nAlt+Click pour ouvrir le lorebook", + "world_button_title": "Lore de personnage\n\nCliquer pour charger\nMajuscule/Alt-clic ou appui long pour ouvrir la fenêtre contextuelle « Lien vers le World Info ».", + "chat_lorebook_button_title": "Lore du chat\n\nCliquer pour charger\nMajuscule/Alt-clic ou appui long pour ouvrir la fenêtre contextuelle « Lien vers le Lorebook du chat ».", "Manual": "Manuel", "Duplicate persona": "Dupliquer la persona", "popup-button-crop": "Recadrer", @@ -2012,7 +2014,7 @@ "Downloader Options": "Options de téléchargement", "Extra parameters for downloading/HuggingFace API": "Paramètres supplémentaires pour le téléchargement/HuggingFace API.\rSi vous n'êtes pas sûr, laissez ces paramètres vides.", "Revision": "Révision", - "Folder Name": "Nom du dossier de sortie", + "Output Folder Name": "Nom du dossier de sortie", "HF Token": "Token HF", "Include Patterns": "Inclure les patterns", "Glob patterns of files to include in the download.": "Patterns globaux de fichiers à inclure dans le téléchargement.\rSéparer chaque pattern par une nouvelle ligne.", @@ -2046,5 +2048,19 @@ "System Prompt Name": "Nom du prompt système:", "Instruct Mode": "Mode Instruction:", "Save and Update": "Sauvegarder et mettre à jour", - "Don't ask again for this URL": "Ne plus demander pour cette URL" + "Don't ask again for this URL": "Ne plus demander pour cette URL", + "Interleaved Thinking": "Raisonnement intercalé", + "Since Last User Message": "Depuis le dernier message utilisateur", + "Active Tool Chain": "Chaîne d'outils active", + "openrouter_interleaved_thinking_hint": "Envoie le raisonnement des tours précédents de l'assistant avec les requêtes d'outils pour conserver le contexte du raisonnement intercalé.", + "SillyTavern Logo": "Logo SillyTavern", + "Initializing…": "Initialisation…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "Nom non accepté, car il est identique à l'ancien (en ignorant la casse et les accents).", + "Rename Chat": "Renommer la discussion", + "Renaming chat…": "Renommage de la discussion…", + "Delete Chat": "Supprimer la discussion", + "Deleting chat…": "Suppression de la discussion…", + "Loading chat…": "Chargement de la discussion…", + "Bulk Delete": "Suppression groupée", + "Deleting ${0} character(s)…": "Suppression de ${0} personnage(s)…" } diff --git a/src/locales/is-is.json b/src/locales/is-is.json index c48ecafe..9c15493a 100644 --- a/src/locales/is-is.json +++ b/src/locales/is-is.json @@ -335,6 +335,8 @@ "koboldcpp API key (optional)": "koboldcpp API lykill (valfrjálst)", "Example: http://127.0.0.1:5001": "Dæmi: http://127.0.0.1:5001", "Authorize": "Heimild", + "OpenRouter API key already exists": "OpenRouter API lykill er þegar til", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "Viltu virkilega búa til nýjan OpenRouter lykil? Núverandi lykill þinn verður ekki eytt.", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Fáðu API lykilinn þinn fyrir OpenRouter með því að nota OAuth strauminn. Þú verður endurvísað(ð/ur) á openrouter.ai", "Bypass status check": "Hlaupa framhjá stöðutík", "Chat Completion Source": "Heimild að fullvirkni spjalls", @@ -1436,5 +1438,19 @@ "Still have questions?": "Ertu enn með spurningar?", "Join the SillyTavern Discord": "Skráðu þig í SillyTavern Discord", "Post a GitHub issue": "Senda inn GitHub málefni", - "Contact the developers": "Hafa samband við þróunaraðila" + "Contact the developers": "Hafa samband við þróunaraðila", + "Interleaved Thinking": "Fléttuð hugsun", + "Since Last User Message": "Frá síðustu notandaskilaboðum", + "Active Tool Chain": "Virk verkfærakeðja", + "openrouter_interleaved_thinking_hint": "Sendir röksemdir úr fyrri aðstoðarskilaboðum með verkfæraköllum til að viðhalda samhengi fléttaðrar hugsunar.", + "SillyTavern Logo": "SillyTavern merki", + "Initializing…": "Ræsir…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "Nafn ekki samþykkt, því það er það sama og áður (hunsar há-/lágstafi og brottmerki).", + "Rename Chat": "Endurnefna spjall", + "Renaming chat…": "Endurnefni spjall…", + "Delete Chat": "Eyða spjalli", + "Deleting chat…": "Eyði spjalli…", + "Loading chat…": "Hleð spjalli…", + "Bulk Delete": "Fjöldaeyðing", + "Deleting ${0} character(s)…": "Eyði ${0} persónu(m)…" } diff --git a/src/locales/it-it.json b/src/locales/it-it.json index 7240c58b..afcb15ea 100644 --- a/src/locales/it-it.json +++ b/src/locales/it-it.json @@ -337,6 +337,8 @@ "koboldcpp API key (optional)": "Chiave API koboldcpp (opzionale)", "Example: http://127.0.0.1:5001": "Esempio: http://127.0.0.1:5001", "Authorize": "Autorizzare", + "OpenRouter API key already exists": "La chiave API di OpenRouter esiste già", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "Desideri veramente creare una nuova chiave API di OpenRouter? La tua chiave esistente non verrà eliminata.", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Ottieni il tuo token API di OpenRouter utilizzando il flusso OAuth. Sarai reindirizzato su openrouter.ai", "Bypass status check": "Ignora controllo stato", "Chat Completion Source": "Fonte di Completamento della Chat", @@ -1438,5 +1440,19 @@ "Still have questions?": "Hai ancora domande?", "Join the SillyTavern Discord": "Unisciti al SillyTavern Discord", "Post a GitHub issue": "Pubblica un problema su GitHub", - "Contact the developers": "Contatta gli sviluppatori" + "Contact the developers": "Contatta gli sviluppatori", + "Interleaved Thinking": "Ragionamento intercalato", + "Since Last User Message": "Dall'ultimo messaggio utente", + "Active Tool Chain": "Catena di strumenti attiva", + "openrouter_interleaved_thinking_hint": "Invia il ragionamento dai turni precedenti dell'assistente con le richieste di strumenti per mantenere il contesto del ragionamento intercalato.", + "SillyTavern Logo": "Logo SillyTavern", + "Initializing…": "Inizializzazione…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "Nome non accettato, poiché è lo stesso di prima (ignorando maiuscole e accenti).", + "Rename Chat": "Rinomina chat", + "Renaming chat…": "Rinominazione chat…", + "Delete Chat": "Elimina chat", + "Deleting chat…": "Eliminazione chat…", + "Loading chat…": "Caricamento chat…", + "Bulk Delete": "Eliminazione multipla", + "Deleting ${0} character(s)…": "Eliminazione di ${0} personaggio/i…" } diff --git a/src/locales/ja-jp.json b/src/locales/ja-jp.json index 63150394..b15d600b 100644 --- a/src/locales/ja-jp.json +++ b/src/locales/ja-jp.json @@ -337,6 +337,8 @@ "koboldcpp API key (optional)": "koboldcpp API キー (オプション)", "Example: http://127.0.0.1:5001": "例: http://127.0.0.1:5001", "Authorize": "承認", + "OpenRouter API key already exists": "OpenRouter API キーは既に存在します", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "新しい OpenRouter キーを作成してもよろしいですか?既存のキーは削除されません。", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "OAuthフローを使用してOpenRouter APIトークンを取得します。 openrouter.aiにリダイレクトされます", "Bypass status check": "ステータスのチェックをバイパスする", "Chat Completion Source": "チャット補完ソース", @@ -1443,5 +1445,19 @@ "Contact the developers": "開発者に連絡", "Stop Inspecting": "検査を停止", "Inspect Prompts": "プロンプトを検査", - "Toggle prompt inspection": "プロンプト検査の切り替え" + "Toggle prompt inspection": "プロンプト検査の切り替え", + "Interleaved Thinking": "インターリーブ思考", + "Since Last User Message": "直前のユーザーメッセージ以降", + "Active Tool Chain": "アクティブなツールチェーン", + "openrouter_interleaved_thinking_hint": "インターリーブ思考の文脈を維持するため、直前のアシスタントターンの推論をツール呼び出しリクエストとともに送信します。", + "SillyTavern Logo": "SillyTavernロゴ", + "Initializing…": "初期化中…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "名前が受け入れられませんでした。以前と同じです(大文字小文字とアクセントを無視)。", + "Rename Chat": "チャット名を変更", + "Renaming chat…": "チャット名を変更中…", + "Delete Chat": "チャットを削除", + "Deleting chat…": "チャットを削除中…", + "Loading chat…": "チャットを読み込み中…", + "Bulk Delete": "一括削除", + "Deleting ${0} character(s)…": "${0}人のキャラクターを削除中…" } diff --git a/src/locales/ko-kr.json b/src/locales/ko-kr.json index 3839d85c..c54f2763 100644 --- a/src/locales/ko-kr.json +++ b/src/locales/ko-kr.json @@ -337,6 +337,8 @@ "koboldcpp API key (optional)": "koboldcpp API 키(선택사항)", "Example: http://127.0.0.1:5001": "예: http://127.0.0.1:5001", "Authorize": "승인하기", + "OpenRouter API key already exists": "OpenRouter API 키가 이미 존재합니다", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "정말 새로운 OpenRouter 키를 만들기를 원하십니까? 기존 키는 삭제되지 않습니다.", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "OAuth 플로우를 사용하여 OpenRouter API 토큰을 가져옵니다. openrouter.ai로 리디렉션됩니다.", "Legacy API (pre-OAI, no streaming)": "레거시 API (OAI 이전, 스트리밍 없음)", "Bypass status check": "상태 확인 우회", @@ -1533,7 +1535,7 @@ "Only apply color as accent": "색상은 오직 강조로써만 적용됩니다", "qr--colorClear": "색상 지우기", "Color": "색상", - "world_button_title": "캐릭터 로어. 클릭하여 로드하세요. Shift를 클릭하면 '월드 인포 링크' 팝업이 열립니다.", + "world_button_title": "캐릭터 로어. 클릭하여 로드하세요. Shift/Alt+클릭 또는 길게 누르면 '월드 인포 링크' 팝업이 열립니다.", "Select TTS Provider": "TTS 공급자 선택", "tts_enabled": "활성화", "Narrate user messages": "사용자 메시지 나레이션", @@ -1617,5 +1619,19 @@ "to install additional features.": "으로 가세요.", "Master Import": "마스터 불러오기", "Master Export": "마스터 내보내기", - "Chat Quick Reply Sets": "채팅 빠른 답장 세트들" + "Chat Quick Reply Sets": "채팅 빠른 답장 세트들", + "Interleaved Thinking": "인터리브드 사고", + "Since Last User Message": "마지막 사용자 메시지 이후", + "Active Tool Chain": "활성 도구 체인", + "openrouter_interleaved_thinking_hint": "인터리브드 사고 컨텍스트를 유지하기 위해 이전 어시스턴트 턴의 추론을 도구 호출 요청과 함께 전송합니다.", + "SillyTavern Logo": "SillyTavern 로고", + "Initializing…": "초기화 중…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "이름이 승인되지 않았습니다. 이전과 동일합니다(대소문자 및 악센트 무시).", + "Rename Chat": "채팅 이름 변경", + "Renaming chat…": "채팅 이름 변경 중…", + "Delete Chat": "채팅 삭제", + "Deleting chat…": "채팅 삭제 중…", + "Loading chat…": "채팅 불러오는 중…", + "Bulk Delete": "대량 삭제", + "Deleting ${0} character(s)…": "${0}개 캐릭터 삭제 중…" } diff --git a/src/locales/nl-nl.json b/src/locales/nl-nl.json index ddfa09f8..8af57f55 100644 --- a/src/locales/nl-nl.json +++ b/src/locales/nl-nl.json @@ -333,6 +333,8 @@ "koboldcpp API key (optional)": "koboldcpp API-sleutel (optioneel)", "Example: http://127.0.0.1:5001": "Voorbeeld: http://127.0.0.1:5001", "Authorize": "Toestemming geven", + "OpenRouter API key already exists": "OpenRouter API-sleutel bestaat al", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "Wilt u echt een nieuwe OpenRouter API-sleutel maken? Uw bestaande sleutel wordt niet verwijderd.", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Haal uw OpenRouter API-token op met behulp van OAuth-flow. U wordt doorgestuurd naar openrouter.ai", "Bypass status check": "Omzeil statuscontrole", "Chat Completion Source": "Bron voor Chatvoltooiing", @@ -1434,5 +1436,19 @@ "Still have questions?": "Heb je nog vragen?", "Join the SillyTavern Discord": "Word lid van de SillyTavern Discord", "Post a GitHub issue": "Plaats een GitHub-probleem", - "Contact the developers": "Neem contact op met de ontwikkelaars" + "Contact the developers": "Neem contact op met de ontwikkelaars", + "Interleaved Thinking": "Verweven redenering", + "Since Last User Message": "Sinds laatste gebruikersbericht", + "Active Tool Chain": "Actieve toolketen", + "openrouter_interleaved_thinking_hint": "Verstuurt redenering uit eerdere assistentbeurten met tool-aanvragen om de context van verweven redenering te behouden.", + "SillyTavern Logo": "SillyTavern-logo", + "Initializing…": "Initialiseren…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "Naam niet geaccepteerd, omdat deze hetzelfde is als voorheen (hoofdletters en accenten genegeerd).", + "Rename Chat": "Chat hernoemen", + "Renaming chat…": "Chat hernoemen…", + "Delete Chat": "Chat verwijderen", + "Deleting chat…": "Chat verwijderen…", + "Loading chat…": "Chat laden…", + "Bulk Delete": "Bulkverwijdering", + "Deleting ${0} character(s)…": "${0} personage(s) verwijderen…" } diff --git a/src/locales/pt-pt.json b/src/locales/pt-pt.json index 223464b3..fac3cd2a 100644 --- a/src/locales/pt-pt.json +++ b/src/locales/pt-pt.json @@ -335,6 +335,8 @@ "koboldcpp API key (optional)": "Chave API koboldcpp (opcional)", "Example: http://127.0.0.1:5001": "Exemplo: http://127.0.0.1:5001", "Authorize": "Autorizar", + "OpenRouter API key already exists": "A chave de API do OpenRouter já existe", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "Você realmente deseja criar uma nova chave OpenRouter? Sua chave existente não será excluída.", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Obtenha seu token da API do OpenRouter usando o fluxo OAuth. Você será redirecionado para openrouter.ai", "Bypass status check": "Ignorar verificação de status", "Chat Completion Source": "Fonte de conclusão de chat", @@ -1436,5 +1438,19 @@ "Still have questions?": "Ainda tem perguntas?", "Join the SillyTavern Discord": "Junte-se ao Discord do SillyTavern", "Post a GitHub issue": "Publicar um problema no GitHub", - "Contact the developers": "Contatar os desenvolvedores" + "Contact the developers": "Contatar os desenvolvedores", + "Interleaved Thinking": "Raciocínio intercalado", + "Since Last User Message": "Desde a última mensagem do utilizador", + "Active Tool Chain": "Cadeia de ferramentas ativa", + "openrouter_interleaved_thinking_hint": "Envia o raciocínio de turnos anteriores do assistente com pedidos de ferramentas para manter o contexto de raciocínio intercalado.", + "SillyTavern Logo": "Logótipo do SillyTavern", + "Initializing…": "A inicializar…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "Nome não aceite, pois é o mesmo que antes (ignorando maiúsculas e acentos).", + "Rename Chat": "Renomear chat", + "Renaming chat…": "A renomear chat…", + "Delete Chat": "Eliminar chat", + "Deleting chat…": "A eliminar chat…", + "Loading chat…": "A carregar chat…", + "Bulk Delete": "Eliminação em massa", + "Deleting ${0} character(s)…": "A eliminar ${0} personagem(ns)…" } diff --git a/src/locales/ru-ru.json b/src/locales/ru-ru.json index 57cc0bbf..6be63c09 100644 --- a/src/locales/ru-ru.json +++ b/src/locales/ru-ru.json @@ -758,6 +758,8 @@ "Doesn't work? Try adding": "Не работает? Попробуйте добавить в конце", "at the end!": "!", "Authorize": "Авторизоваться", + "OpenRouter API key already exists": "Ключ API OpenRouter уже существует", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "Вы действительно хотите создать новый ключ OpenRouter? Ваш существующий ключ не будет удален.", "No persona description": "[Нет описания]", "Not connected to API!": "Нет соединения с API!", "Type a message, or /? for help": "Введите сообщение, или /? для получения справки", @@ -1902,7 +1904,7 @@ "Save": "Сохранить", "Chat Lorebook": "Лорбук для чата", "chat_world_template_txt": "Выбранный мир будет привязан к этому чату. Будет работать наряду с глобальным лорбуком и лором персонажа.", - "world_button_title": "Лор персонажа\n\nНажмите, чтобы загрузить\nShift + ЛКМ, чтобы открыть диалог привязки мира", + "world_button_title": "Лор персонажа\n\nНажмите, чтобы загрузить\nShift / Alt + ЛКМ или долгое нажатие, чтобы открыть диалог привязки мира", "No auxillary Lorebooks set. Click here to select.": "Вспомогательный лорбук не выбран. Нажмите, чтобы выбрать.", "ext_regex_user_input_desc": "Отправленные вами сообщения.", "ext_regex_ai_input_desc": "Полученные от API ответы.", @@ -2128,7 +2130,7 @@ "openai_reasoning_effort_low": "Поверхностные", "openai_reasoning_effort_medium": "Обычные", "openai_reasoning_effort_high": "Подробные", - "Persona Lore Alt+Click to open the lorebook": "Лорбук данной персоны\nAlt + ЛКМ чтобы открыть лорбук", + "persona_lore_button_title": "Лорбук данной персоны\n\nНажмите, чтобы открыть\nShift / Alt + ЛКМ или долгое нажатие, чтобы открыть диалог привязки лорбука", "Persona Lorebook for": "Лорбук для персоны", "persona_world_template_txt": "Выбранный мир будет привязан к этой персоне. Будет работать вместе с глобальным лорбуком и лорбуками персонажа и чата.", "Global list": "Глобальный список", @@ -2143,7 +2145,7 @@ "Enter a valid API URL": "Введите корректный адрес API", "No Ollama model selected.": "Не выбрана модель Ollama", "Background Fitting": "Способ подгонки фона под разрешение", - "Chat Lore Alt+Click to open the lorebook": "Лорбук данного чата\nAlt + ЛКМ чтобы открыть лорбук", + "chat_lorebook_button_title": "Лорбук данного чата\n\nНажмите, чтобы открыть\nShift / Alt + ЛКМ или долгое нажатие, чтобы открыть диалог привязки лорбука", "Token Counter": "Подсчитать токены", "Type / paste in the box below to see the number of tokens in the text.": "Введите или вставьте текст в окошко ниже, чтобы подсчитать количество токенов в нём.", "Selected tokenizer:": "Выбранный токенайзер:", @@ -2738,5 +2740,19 @@ "Uses the voices provided by your operating system": "Используем стандартные голоса вашей ОС", "Your browser or operating system doesn't support speech synthesis": "Ваш браузер либо ОС не поддерживают синтез речи", "Works best when: Pass Asterisks to TTS Engine is enabled, and both Only narrate quotes and Ignore *text, even 'quotes', inside asterisks* are disabled.": "Работает лучше всего, когда: одновременно включена опция \"Передавать звёздочки TTS-движку\", а также отключены обе опции: \"Не озвучивать *текст, даже \"в кавычках\", если он внутри звёздочек*\", и \"Озвучивать только текст \"в кавычках\"\"", - "Available voices": "Доступные голоса" + "Available voices": "Доступные голоса", + "Interleaved Thinking": "Чередующееся рассуждение", + "Since Last User Message": "С момента последнего сообщения пользователя", + "Active Tool Chain": "Активная цепочка инструментов", + "openrouter_interleaved_thinking_hint": "Отправляет рассуждение из предыдущих ходов ассистента вместе с запросами вызова инструментов, чтобы сохранять контекст чередующегося рассуждения.", + "SillyTavern Logo": "Логотип SillyTavern", + "Initializing…": "Инициализация…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "Имя не принято, так как оно совпадает с предыдущим (игнорируя регистр и акценты).", + "Rename Chat": "Переименовать чат", + "Renaming chat…": "Переименование чата…", + "Delete Chat": "Удалить чат", + "Deleting chat…": "Удаление чата…", + "Loading chat…": "Загрузка чата…", + "Bulk Delete": "Массовое удаление", + "Deleting ${0} character(s)…": "Удаление ${0} персонажа(ей)…" } diff --git a/src/locales/th-th.json b/src/locales/th-th.json index 405571df..21dee67f 100644 --- a/src/locales/th-th.json +++ b/src/locales/th-th.json @@ -339,6 +339,8 @@ "koboldcpp API key (optional)": "คีย์ API ของ koboldcpp (เพิ่มเติม)", "Example: http://127.0.0.1:5001": "ตัวอย่าง: http://127.0.0.1:5001", "Authorize": "อนุญาต", + "OpenRouter API key already exists": "คีย์ API ของ OpenRouter มีอยู่แล้ว", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "คุณต้องการสร้างคีย์ OpenRouter ใหม่จริง ๆ หรือไม่ คีย์ที่มีอยู่ของคุณจะไม่ถูกลบ", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "โปรดเข้าสู่ระบบเพื่อรับ OpenRouter API Token โดยใช้ OAuth Flow จากนั้นคุณจะถูกเปลี่ยนเส้นทางไปยังเว็บไซต์ของ openrouter.ai", "Bypass status check": "ข้ามการตรวจสอบสถานะ", "Chat Completion Source": "แหล่งที่มาของ Chat Completion", @@ -1455,5 +1457,19 @@ "Contact the developers": "ติดต่อผู้พัฒนา", "Stop Inspecting": "Stop Inspecting", "Inspect Prompts": "ตรวจสอบ Prompt", - "Toggle prompt inspection": "สลับการตรวจสอบ Prompt" + "Toggle prompt inspection": "สลับการตรวจสอบ Prompt", + "Interleaved Thinking": "การคิดแบบสลับขั้น", + "Since Last User Message": "ตั้งแต่ข้อความล่าสุดของผู้ใช้", + "Active Tool Chain": "สายโซ่เครื่องมือที่ใช้งานอยู่", + "openrouter_interleaved_thinking_hint": "ส่งเหตุผลจากเทิร์นก่อนหน้าของผู้ช่วยไปพร้อมกับคำขอเรียกใช้เครื่องมือ เพื่อคงบริบทการคิดแบบสลับขั้นไว้", + "SillyTavern Logo": "โลโก้ SillyTavern", + "Initializing…": "กำลังเริ่มต้น…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "ชื่อไม่ได้รับการยอมรับ เนื่องจากเหมือนกับก่อนหน้านี้ (ไม่สนใจตัวพิมพ์ใหญ่เล็กและเครื่องหมายเสียง)", + "Rename Chat": "เปลี่ยนชื่อแชท", + "Renaming chat…": "กำลังเปลี่ยนชื่อแชท…", + "Delete Chat": "ลบแชท", + "Deleting chat…": "กำลังลบแชท…", + "Loading chat…": "กำลังโหลดแชท…", + "Bulk Delete": "ลบจำนวนมาก", + "Deleting ${0} character(s)…": "กำลังลบ ${0} ตัวละคร…" } diff --git a/src/locales/uk-ua.json b/src/locales/uk-ua.json index 166a685f..5179547b 100644 --- a/src/locales/uk-ua.json +++ b/src/locales/uk-ua.json @@ -335,6 +335,8 @@ "koboldcpp API key (optional)": "API-ключ koboldcpp (необов’язково)", "Example: http://127.0.0.1:5001": "Приклад: http://127.0.0.1:5001", "Authorize": "Авторизувати", + "OpenRouter API key already exists": "API ключ OpenRouter вже існує", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "Ви дійсно бажаєте створити новий ключ OpenRouter API? Ваш існуючий ключ не буде видалено.", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Отримайте свій токен API OpenRouter за допомогою OAuth. Вас буде перенаправлено на openrouter.ai", "Bypass status check": "Обійти перевірку статусу", "Chat Completion Source": "Джерело Chat Completion", @@ -1436,5 +1438,19 @@ "Still have questions?": "Все ще є питання?", "Join the SillyTavern Discord": "Приєднуйтесь до SillyTavern Discord", "Post a GitHub issue": "Опублікуйте проблему на GitHub", - "Contact the developers": "Зв'яжіться з розробниками" + "Contact the developers": "Зв'яжіться з розробниками", + "Interleaved Thinking": "Черговане мислення", + "Since Last User Message": "Від останнього повідомлення користувача", + "Active Tool Chain": "Активний ланцюжок інструментів", + "openrouter_interleaved_thinking_hint": "Надсилає міркування з попередніх ходів асистента разом із запитами виклику інструментів, щоб зберегти контекст чергованого мислення.", + "SillyTavern Logo": "Логотип SillyTavern", + "Initializing…": "Ініціалізація…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "Ім'я не прийнято, оскільки воно збігається з попереднім (ігноруючи регістр та акценти).", + "Rename Chat": "Перейменувати чат", + "Renaming chat…": "Перейменування чату…", + "Delete Chat": "Видалити чат", + "Deleting chat…": "Видалення чату…", + "Loading chat…": "Завантаження чату…", + "Bulk Delete": "Масове видалення", + "Deleting ${0} character(s)…": "Видалення ${0} персонажа(ів)…" } diff --git a/src/locales/vi-vn.json b/src/locales/vi-vn.json index 0e6290f7..823c7fe7 100644 --- a/src/locales/vi-vn.json +++ b/src/locales/vi-vn.json @@ -335,6 +335,8 @@ "koboldcpp API key (optional)": "Key API koboldcpp (tùy chọn)", "Example: http://127.0.0.1:5001": "Ví dụ: http://127.0.0.1:5001", "Cho phép": "Ủy quyền", + "OpenRouter API key already exists": "Key API OpenRouter đã tồn tại", + "Do you really wish to create a new OpenRouter key? Your existing key will not be deleted.": "Bạn có thực sự muốn tạo khóa OpenRouter mới không? Khóa hiện có của bạn sẽ không bị xóa.", "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Nhận mã thông báo API OpenRouter của bạn bằng cách sử dụng luồng OAuth. Bạn sẽ được chuyển hướng đến openrouter.ai", "Bypass status check": "Bỏ qua check trạng thái", "Chat Completion Source": "Nguồn cho Chat Completion", @@ -1436,5 +1438,19 @@ "Still have questions?": "Bạn còn thắc mắc?", "Join the SillyTavern Discord": "Tham gia Kênh Discord của SillyTavern", "Post a GitHub issue": "Đăng một vấn đề trên GitHub", - "Contact the developers": "Liên hệ với Devs" + "Contact the developers": "Liên hệ với Devs", + "Interleaved Thinking": "Lập luận xen kẽ", + "Since Last User Message": "Kể từ tin nhắn người dùng gần nhất", + "Active Tool Chain": "Chuỗi công cụ đang hoạt động", + "openrouter_interleaved_thinking_hint": "Gửi lập luận từ các lượt trợ lý trước đó cùng với yêu cầu gọi công cụ để duy trì ngữ cảnh lập luận xen kẽ.", + "SillyTavern Logo": "Logo SillyTavern", + "Initializing…": "Đang khởi tạo…", + "Name not accepted, as it is the same as before (ignoring case and accents).": "Tên không được chấp nhận vì giống như trước đó (bỏ qua chữ hoa/thường và dấu).", + "Rename Chat": "Đổi tên cuộc trò chuyện", + "Renaming chat…": "Đang đổi tên cuộc trò chuyện…", + "Delete Chat": "Xóa cuộc trò chuyện", + "Deleting chat…": "Đang xóa cuộc trò chuyện…", + "Loading chat…": "Đang tải cuộc trò chuyện…", + "Bulk Delete": "Xóa hàng loạt", + "Deleting ${0} character(s)…": "Đang xóa ${0} nhân vật…" } diff --git a/src/script.js b/src/script.js index c8a90d03..db7f38f9 100644 --- a/src/script.js +++ b/src/script.js @@ -266,7 +266,7 @@ import { tag_import_setting, applyCharacterTagsToMessageDivs, } from './scripts/tags.js'; -import { initSecrets, primeSecretStateSnapshot, readSecretState } from './scripts/secrets.js'; +import { checkOpenRouterAuth, initSecrets, primeSecretStateSnapshot, readSecretState } from './scripts/secrets.js'; import { markdownExclusionExt } from './scripts/showdown-exclusion.js'; import { markdownUnderscoreExt } from './scripts/showdown-underscore.js'; import { NOTE_MODULE_NAME, initAuthorsNote, metadata_keys, setFloatingPrompt, shouldWIAddPrompt } from './scripts/authors-note.js'; @@ -299,6 +299,7 @@ import { } from './scripts/personas.js'; import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js'; import { hideLoader, showLoader, removePreloader } from './scripts/loader.js'; +import { loader } from './scripts/action-loader.js'; import { BulkEditOverlay } from './scripts/BulkEditOverlay.js'; import { initTextGenModels } from './scripts/textgen-models.js'; import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, preserveNeutralChat, restoreNeutralChat, formatCreatorNotes, initChatUtilities, addDOMPurifyHooks } from './scripts/chats.js'; @@ -351,6 +352,8 @@ import { MacroEngine } from './scripts/macros/engine/MacroEngine.js'; import { addChatBackupsBrowser } from './scripts/chat-backups.js'; import { onboardingExperimentalMacroEngine } from './scripts/macros/engine/MacroDiagnostics.js'; import { createStartupStatusOverlay } from './scripts/tauri/startup/startup-status-overlay.js'; +import { compressRequest, setRequestCompressionConfig } from './scripts/request-compression.js'; +import { canJumpToSwipeForMessage, canOpenSwipePickerForMessage, initSwipePicker } from './scripts/swipe-picker.js'; // API OBJECT FOR EXTERNAL WIRING globalThis.SillyTavern = { @@ -396,6 +399,8 @@ export { setCharacterSettingsOverrides as setScenarioOverride, /** @deprecated Use appendMediaToMessage instead. */ appendMediaToMessage as appendImageToMessage, + /** @deprecated Use getMaxPromptTokens instead. */ + getMaxPromptTokens as getMaxContextSize, }; /** @@ -428,12 +433,36 @@ toastr.options = { // so the toasts still show up inside there. fixToastrForDialogs(); }, - onShown: function () { - // Set tooltip to the notification message - $(this).attr('title', t`Tap to close`); - }, }; +// Run once during startup +toastr.subscribe(function (args) { + if (args.state !== 'visible') { + return; + } + + const $container = toastr.getContainer(args.options, false); + if (!$container || !$container.length) { + return; + } + + // toastr has already inserted the element at this point + const $toast = args.options.newestOnTop + ? $container.children().first() + : $container.children().last(); + + // Meaning of "clickable": + // Interactable unless tapToDismiss was explicitly false + const isInteractable = args.options.tapToDismiss !== false; + $toast.toggleClass('interactable', isInteractable); + if (isInteractable) { + $toast.attr('title', t`Tap to close`); + } else { + $toast.removeAttr('title'); + $toast.addClass('toast-non-interactable'); + } +}); + const TAURI_BACKEND_ERROR_EVENT = 'tauritavern:backend-error'; const TAURI_BACKEND_ERROR_QUEUE_KEY = '__TAURITAVERN_BACKEND_ERROR_QUEUE__'; const TAURI_BACKEND_ERROR_READY_KEY = '__TAURITAVERN_BACKEND_ERROR_CONSUMER_READY__'; @@ -682,8 +711,7 @@ export function reloadMarkdownProcessor() { export function getCurrentChatId() { if (selected_group) { return groups.find(x => x.id == selected_group)?.chat_id; - } - else if (this_chid !== undefined) { + } else if (this_chid !== undefined) { return characters[this_chid]?.chat; } } @@ -794,8 +822,7 @@ export let recentSwipes = 0; export let extension_prompts = {}; export let main_api;// = "kobold"; -/** @type {AbortController} */ -let abortController; +let abortController = new AbortController(); //css var css_send_form_display = $('
').css('display'); @@ -956,6 +983,7 @@ async function firstLoadInit() { await initPresetManager(); await initSystemMessages(); await applySettingsSnapshot(bootstrapSnapshot.settings); + await checkOpenRouterAuth(); syncMobileImmersiveFullscreenUi(); initKeyboard(); initDynamicStyles(); @@ -991,6 +1019,7 @@ async function firstLoadInit() { initDataMaid(); initItemizedPrompts(); initAccessibility(); + initSwipePicker(); addDebugFunctions(); let deferThirdPartyExtensions = false; @@ -1236,8 +1265,7 @@ function getCharacterBlock(item, id) { const description = item.data?.creator_notes || ''; if (description) { template.find('.ch_description').text(description); - } - else { + } else { template.find('.ch_description').hide(); } @@ -1245,8 +1273,7 @@ function getCharacterBlock(item, id) { const auxFieldValue = (item.data && item.data[auxFieldName]) || ''; if (auxFieldValue) { template.find('.character_version').text(auxFieldValue); - } - else { + } else { template.find('.character_version').hide(); } @@ -2120,11 +2147,9 @@ export async function reloadCurrentChatUnsafe() { if (selected_group) { await getGroupChat(selected_group, true); - } - else if (this_chid !== undefined) { + } else if (this_chid !== undefined) { await getChat(); - } - else { + } else { resetChatState(); restoreNeutralChat(); await getCharacters(); @@ -2392,34 +2417,33 @@ export function messageFormatting(mes, ch_name, isSystem, isUser, messageId, san } /** - * Inserts or replaces an SVG icon adjacent to the provided message's timestamp. + * Creates an Image element for the given API/model icon. + * The image references the matching SVG file from `/img/` and includes a tooltip with API and model info. + * The caller is responsible for appending the image to the DOM and optionally calling `SVGInject` on it. * - * If the `extra.api` is "openai" and `extra.model` contains the substring "claude", - * the function fetches the "claude.svg". Otherwise, it fetches the SVG named after - * the value in `extra.api`. + * @param {string} apiName - API identifier matching an SVG file in /img/ (e.g. 'openai', 'openrouter', 'claude') + * @param {string} [modelName=''] - Model name shown in the tooltip + * @returns {HTMLImageElement} The image element (not yet in the DOM) + */ +export function createModelIcon(apiName, modelName = '') { + const image = new Image(); + image.classList.add('icon-svg'); + image.src = `/img/${apiName}.svg`; + image.title = modelName ? `${apiName} - ${modelName}` : apiName; + return image; +} + +/** + * Inserts or replaces an SVG icon adjacent to the provided message's timestamp. * * @param {JQuery} mes - The message element containing the timestamp where the icon should be inserted or replaced. * @param {ChatMessageExtra} extra - Contains the API and model details. */ function insertSVGIcon(mes, extra) { - // Determine the SVG filename - let modelName; + const apiName = extra?.api || ''; - // Claude on OpenRouter or Anthropic - if (extra.api === 'openai' && extra.model?.toLowerCase().includes('claude')) { - modelName = 'claude'; - } - // OpenAI on OpenRouter - else if (extra.api === 'openai' && extra.model?.toLowerCase().includes('openai')) { - modelName = 'openai'; - } - // OpenRouter website model or other models - else if (extra.api === 'openai' && (extra.model === null || extra.model?.toLowerCase().includes('/'))) { - modelName = 'openrouter'; - } - // Everything else - else { - modelName = extra.api; + if (!apiName) { + return; } const insertOrReplaceSVG = (image, className, targetSelector, insertBefore) => { @@ -2435,16 +2459,14 @@ function insertSVGIcon(mes, extra) { }; }; - const createModelImage = (className, targetSelector, insertBefore) => { - const image = new Image(); - image.classList.add('icon-svg', className); - image.src = `/img/${modelName}.svg`; - image.title = `${extra?.api ? extra.api + ' - ' : ''}${extra?.model ?? ''}`; + const insertIcon = (className, targetSelector, insertBefore) => { + const image = createModelIcon(apiName, extra?.model); + image.classList.add(className); insertOrReplaceSVG(image, className, targetSelector, insertBefore); }; - createModelImage('timestamp-icon', '.timestamp'); - createModelImage('thinking-icon', '.mes_reasoning_header_title', true); + insertIcon('timestamp-icon', '.timestamp'); + insertIcon('thinking-icon', '.mes_reasoning_header_title', true); } /** @@ -3065,7 +3087,6 @@ export function addOneMessage(mes, { type = undefined, insertAfter = null, scrol * @returns {JQuery} Rendered HTMLElement. */ export function updateMessageElement(mes, { messageId = chat.length - 1, messageElement = messageTemplate.clone(), adjustMediaScroll = SCROLL_BEHAVIOR.NONE } = {}) { - let avatarImg = getThumbnailUrl('persona', user_avatar); //for non-user messages @@ -3309,6 +3330,7 @@ export function substituteParamsLegacy(content, _name1, _name2, _original, _grou else if (/{{\s*[!?~#/]/.test(content)) feature = 'macro flags'; else if (/{{\s*[.$]/.test(content)) feature = 'variable shorthands'; else if (/\{\{(?:(?!\}\}).)*\{\{(?=[\s\S]*?\}\}[\s\S]*?\}\})/.test(content)) feature = 'nested macro'; + else if (/{{(?:greeting|charFirstMessage)(?:::\d+)?}}/i.test(content)) feature = 'greeting macro'; if (feature) void onboardingExperimentalMacroEngine(feature); } @@ -3433,6 +3455,11 @@ export function substituteParamsLegacy(content, _name1, _name2, _original, _grou export function substituteParams(content, options = {}) { if (!content) return ''; + if (typeof content !== 'string') { + console.warn('substituteParams: content will be coerced to string', content); + content = String(content); + } + // Handle legacy signature calls to substituteParams // We'll simply re-route them to a temporary legacy function. In the future, we'll remove this and cleanly build the options object ourselves. const isOptionsObject = options && typeof options === 'object' && !Array.isArray(options); @@ -3466,9 +3493,15 @@ export function substituteParams(content, options = {}) { * Gets stopping sequences for the prompt. * @param {boolean} isImpersonate A request is made to impersonate a user * @param {boolean} isContinue A request is made to continue the message + * @param {string} [api] Optional API name to get API-specific stopping sequences for * @returns {string[]} Array of stopping strings */ -export function getStoppingStrings(isImpersonate, isContinue) { +export function getStoppingStrings(isImpersonate, isContinue, api = main_api) { + // Only custom stop strings apply to Chat Completion + if (api === 'openai') { + return getCustomStoppingStrings(); + } + const result = []; if (power_user.context.names_as_stop_strings) { @@ -3804,11 +3837,13 @@ export function baseChatReplace(value, name1Override = null, name2Override = nul * @property {string} version Character version * @property {string} charDepthPrompt Character depth note * @property {string} creatorNotes Character creator notes + * @property {string} firstMessage Character first message / greeting + * @property {string[]} alternateGreetings Character alternate greetings */ /** * Helper to create an object with lazy, memoized getters from a map of field resolvers. - * @param {Record string>} resolvers Map of field names to resolver functions + * @param {Record string|string[]>} resolvers Map of field names to resolver functions * @returns {CharacterCardFields} Object with lazy getters */ export function createLazyFields(resolvers) { @@ -3846,7 +3881,7 @@ export function getCharacterCardFieldsLazy({ chid = undefined } = {}) { const useGroupCards = selected_group && character; const groupCardsLazy = useGroupCards ? getGroupCharacterCardsLazy(selected_group, Number(currentChid)) : null; - /** @type {Record string>} */ + /** @type {Record string|string[]>} */ const resolvers = { persona: () => baseChatReplace(power_user.persona_description?.trim()), system: () => { @@ -3890,6 +3925,17 @@ export function getCharacterCardFieldsLazy({ chid = undefined } = {}) { const exampleDialog = chat_metadata.mes_example || character.mes_example || ''; return baseChatReplace(exampleDialog.trim()); }, + firstMessage: () => { + if (!character) return ''; + const firstMes = character.first_mes?.trim() || ''; + return baseChatReplace(firstMes); + }, + alternateGreetings: () => { + if (!character) return []; + const altGreetings = character.data?.alternate_greetings; + if (!Array.isArray(altGreetings)) return []; + return altGreetings.map(greeting => baseChatReplace(greeting?.trim())); + }, }; return createLazyFields(resolvers); @@ -3916,6 +3962,8 @@ export function getCharacterCardFields({ chid = undefined } = {}) { version: lazy.version, charDepthPrompt: lazy.charDepthPrompt, creatorNotes: lazy.creatorNotes, + firstMessage: lazy.firstMessage, + alternateGreetings: lazy.alternateGreetings, }; } @@ -4172,7 +4220,16 @@ class StreamingProcessor { } } - async onFinishStreaming(messageId, text) { + /** + * Finalizes an intermediary message after generation is complete, or a tool call is performed. + * Performs essential message processing (code blocks, reasoning, swipes, attachments, events) + * without the heavier finish operations (UI unlock - optional, auto-swipe, sound, save chat). + * @param {number} messageId - The message ID to finalize. + * @param {string} text - The message text. + * @param {Object} options - Additional options for finalization. + * @param {boolean} options.unlockUI - Whether to unlock the generation UI. + */ + async finalizeIntermediaryMessage(messageId, text, { unlockUI = true }) { await this.onProgressStreaming(messageId, text, true); const messageElement = chatElement.find(`.mes[mesid="${messageId}"]`); const message = chat[messageId]; @@ -4215,7 +4272,9 @@ class StreamingProcessor { message.extra.native = this.native; } - this.markUIGenStopped(); + if (unlockUI) { + this.markUIGenStopped(); + } if (this.type !== 'impersonate') { await eventSource.emit(event_types.MESSAGE_RECEIVED, this.messageId, this.type); @@ -4225,6 +4284,10 @@ class StreamingProcessor { } updateSwipeCounter(messageId, { message, messageElement }); + } + + async onFinishStreaming(messageId, text) { + await this.finalizeIntermediaryMessage(messageId, text, { unlockUI: true }); const isAborted = this.abortController.signal.aborted; if (!isAborted && power_user.auto_swipe && generatedTextFiltered(text)) { @@ -4268,9 +4331,9 @@ class StreamingProcessor { } /** - * @returns {Generator<{ text: string, swipes: string[], logprobs: import('./scripts/logprobs.js').TokenLogprobs, toolCalls: any[], state: any }, void, void>} + * @returns {AsyncGenerator<{ text: string, swipes: string[], logprobs: import('./scripts/logprobs.js').TokenLogprobs, toolCalls: any[], state: any }, void, void>} */ - *nullStreamingGeneration() { + async* nullStreamingGeneration() { throw new Error('Generation function for streaming is not hooked up'); } @@ -4285,7 +4348,7 @@ class StreamingProcessor { // when streaming, we cache the result of getStoppingStrings instead of calling it once per token. const isImpersonate = this.type == 'impersonate'; const isContinue = this.type == 'continue'; - this.stoppingStrings = getStoppingStrings(isImpersonate, isContinue); + this.stoppingStrings = getStoppingStrings(isImpersonate, isContinue, main_api); try { const sw = new Stopwatch(1000 / power_user.streaming_fps); @@ -4316,8 +4379,7 @@ class StreamingProcessor { } const seconds = (timestamps[timestamps.length - 1] - timestamps[0]) / 1000; console.warn(`Stream stats: ${timestamps.length} tokens, ${seconds.toFixed(2)} seconds, rate: ${Number(timestamps.length / seconds).toFixed(2)} TPS`); - } - catch (err) { + } catch (err) { // in the case of a self-inflicted abort, we have already cleaned up if (!this.isFinished) { console.error(err); @@ -4346,9 +4408,7 @@ export function createRawPrompt(prompt, api, instructOverride, quietToLoud, syst // If the prompt was given as a string, convert to a message-style object assuming user role if (typeof prompt === 'string') { - const message = api === 'openai' - ? { role: 'user', content: prompt.trim() } - : { role: 'system', content: prompt }; + const message = { role: 'user', content: prompt.trim() }; prompt = [message]; } else { // checks for message-style object if (prompt.length === 0 && !systemPrompt) throw Error('No messages provided'); @@ -4375,7 +4435,12 @@ export function createRawPrompt(prompt, api, instructOverride, quietToLoud, syst // prepend system prompt, if provided if (systemPrompt) { systemPrompt = substituteParams(systemPrompt); - systemPrompt = isInstruct ? (formatInstructModeStoryString(systemPrompt) + '\n') : systemPrompt.trim(); + systemPrompt = isInstruct ? formatInstructModeStoryString(systemPrompt) : systemPrompt.trim(); + if (isInstruct && systemPrompt.length > 0 && !systemPrompt.endsWith('\n')) { + if (power_user.instruct.wrap && !power_user.instruct.story_string_suffix) { + systemPrompt += '\n'; + } + } prompt.unshift({ role: 'system', content: systemPrompt }); } @@ -4396,8 +4461,6 @@ export function createRawPrompt(prompt, api, instructOverride, quietToLoud, syst } /** - * Generates a message using the provided prompt. - * If the prompt is an array of chat-style messages and not using chat completion, it will be converted to a text prompt. * @typedef {object} GenerateRawParams * @prop {string | object[]} [prompt] Prompt to generate a message from. Can be a string or an array of chat-style messages, i.e. [{role: '', content: ''}, ...] * @prop {string} [api] API to use. Main API is used if not specified. @@ -4407,16 +4470,16 @@ export function createRawPrompt(prompt, api, instructOverride, quietToLoud, syst * @prop {number} [responseLength] Maximum response length. If unset, the global default value is used. * @prop {boolean} [trimNames] Whether to allow trimming "{{user}}:" and "{{char}}:" from the response. * @prop {string} [prefill] An optional prefill for the prompt. - * @prop {object} [jsonSchema] JSON schema to use for the structured generation. Usually requires a special instruction. - * @param {GenerateRawParams} params Parameters for generating a message - * @returns {Promise} Generated message + * @prop {JsonSchema} [jsonSchema] JSON schema to use for the structured generation. Usually requires a special instruction. */ -export async function generateRaw({ prompt = '', api = null, instructOverride = false, quietToLoud = false, systemPrompt = '', responseLength = null, trimNames = true, prefill = '', jsonSchema = null } = {}) { - if (arguments.length > 0 && typeof arguments[0] !== 'object') { - console.trace('generateRaw called with positional arguments. Please use an object instead.'); - [prompt, api, instructOverride, quietToLoud, systemPrompt, responseLength, trimNames, prefill, jsonSchema] = arguments; - } +/** + * Generates a raw data object using the provided prompt. + * This used to be part of `generateRaw`, but separating it out allows extensions to access other data such as reasoning message. + * @param {GenerateRawParams} params Parameters for generating a message + * @returns {Promise} Raw API response data, or a JSON string extracted from the response when `jsonSchema` is provided. + */ +export async function generateRawData({ prompt = '', api = null, instructOverride = false, quietToLoud = false, systemPrompt = '', responseLength = null, prefill = '', jsonSchema = null } = {}) { if (!api) { api = main_api; } @@ -4430,7 +4493,10 @@ export async function generateRaw({ prompt = '', api = null, instructOverride = // Allow extensions to stop generation before it happens const eventAbortController = new AbortController(); - const abortHook = () => eventAbortController.abort(new Error('Cancelled by extension')); + const abortHook = () => { + abortController.abort(new Error('Cancelled by stop event')); + eventAbortController.abort(new Error('Cancelled by extension')); + }; eventSource.on(event_types.GENERATION_STOPPED, abortHook); try { @@ -4516,25 +4582,10 @@ export async function generateRaw({ prompt = '', api = null, instructOverride = } if (jsonSchema) { - return extractJsonFromData(data, { mainApi: api }); + return extractJsonFromData(data, { mainApi: api, returnInvalidJson: jsonSchema.returnInvalid }); } - // format result, exclude user prompt bias - const message = cleanUpMessage({ - getMessage: extractMessageFromData(data), - isImpersonate: false, - isContinue: false, - displayIncompleteSentences: true, - includeUserPromptBias: false, - trimNames: trimNames, - trimWrongNames: trimNames, - }); - - if (!message) { - throw new Error('No message generated'); - } - - return message; + return data; } finally { eventSource.removeListener(event_types.GENERATION_STOPPED, abortHook); if (responseLengthCustomized && TempResponseLength.isCustomized()) { @@ -4544,6 +4595,43 @@ export async function generateRaw({ prompt = '', api = null, instructOverride = } } +/** + * Generates a message using the provided prompt. + * If the prompt is an array of chat-style messages and not using chat completion, it will be converted to a text prompt. + * @param {GenerateRawParams} params Parameters for generating a message + * @returns {Promise} Generated output: a cleaned-up message string when `jsonSchema` is not provided, or an extracted JSON string conforming to `jsonSchema` when it is. + */ +export async function generateRaw({ prompt = '', api = null, instructOverride = false, quietToLoud = false, systemPrompt = '', responseLength = null, trimNames = true, prefill = '', jsonSchema = null } = {}) { + if (arguments.length > 0 && typeof arguments[0] !== 'object') { + console.trace('generateRaw called with positional arguments. Please use an object instead.'); + [prompt, api, instructOverride, quietToLoud, systemPrompt, responseLength, trimNames, prefill, jsonSchema] = arguments; + } + + const data = await generateRawData({ prompt, api, instructOverride, quietToLoud, systemPrompt, responseLength, prefill, jsonSchema }); + + // JSON string (matching the provided schema) will already be extracted. + if (jsonSchema) { + return data; + } + + // format result, exclude user prompt bias + const message = cleanUpMessage({ + getMessage: extractMessageFromData(data, api), + isImpersonate: false, + isContinue: false, + displayIncompleteSentences: true, + includeUserPromptBias: false, + trimNames: trimNames, + trimWrongNames: trimNames, + }); + + if (!message) { + throw new Error('No message generated'); + } + + return message; +} + class TempResponseLength { static #originalResponseLength = -1; static #lastApi = null; @@ -4657,6 +4745,7 @@ function removeLastMessage() { * @property {object} value JSON schema value. * @property {string} [description] Description of the schema. * @property {boolean} [strict] If true, the schema will be used in strict mode, meaning that only the fields defined in the schema will be allowed. + * @property {boolean} [returnInvalid] If true, a string that can't be parsed as a JSON will be returned as is, instead of an empty object. * * @typedef {object} GenerateOptions * @property {boolean} [automatic_trigger] If the generation was triggered automatically (e.g. group auto mode). @@ -4781,7 +4870,7 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr if (selected_group && !is_group_generating) { if (!dryRun) { // Returns the promise that generateGroupWrapper returns; resolves when generation is done - return generateGroupWrapper(false, type, { quiet_prompt, force_chid, signal: abortController.signal, quietImage }); + return generateGroupWrapper(false, type, { quiet_prompt, force_chid, signal: abortController.signal, quietImage, jsonSchema }); } const characterIndexMap = new Map(characters.map((char, index) => [char.avatar, index])); @@ -4835,8 +4924,7 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr textareaText = ''; if (chat.length && lastMessage.is_user) { //do nothing? why does this check exist? - } - else if (type !== 'quiet' && type !== 'swipe' && !isImpersonate && !dryRun && !depth && chat.length) { + } else if (type !== 'quiet' && type !== 'swipe' && !isImpersonate && !dryRun && !depth && chat.length) { const deletedAgentStateIds = collectAgentPersistStateIdsFromMessage(chat[chat.length - 1]); deleteItemizedPromptForMessage(chat.length - 1); chat.length = chat.length - 1; @@ -4886,12 +4974,10 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr // If user message contains no text other than bias - send as a system message if (messageBias && !removeMacros(textareaText)) { sendSystemMessage(system_message_types.GENERIC, ' ', { bias: messageBias }); - } - else { + } else { await sendMessageAsUser(textareaText, messageBias); } - } - else if (textareaText == '' && !automatic_trigger && !dryRun && [undefined, 'normal'].includes(type) && main_api == 'openai' && oai_settings.send_if_empty.trim().length > 0 && !depth) { + } else if (textareaText == '' && !automatic_trigger && !dryRun && [undefined, 'normal'].includes(type) && main_api == 'openai' && oai_settings.send_if_empty.trim().length > 0 && !depth) { // Use send_if_empty if set and the user message is empty. Only when sending messages normally await sendMessageAsUser(oai_settings.send_if_empty.trim(), messageBias); } @@ -4925,7 +5011,7 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr } // Determine token limit (used for context backfill and interceptors). - let this_max_context = getMaxContextSize(); + let this_max_context = getMaxPromptTokens(); // First message in fresh 1-on-1 chat reacts to user/character settings changes if (chat.length) { @@ -5027,14 +5113,20 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr for (let i = coreChat.length - 1; i >= 0; i--) { const isPrefix = isContinue && i === coreChat.length - 1; + + // In group chats, only include reasoning from the currently generating character + const isOtherGroupMember = selected_group && coreChat[i].name !== name2; + coreChat[i] = { ...coreChat[i], - mes: promptReasoning.addToMessage( - coreChat[i].mes, - regexedReasoning[i], - isPrefix, - coreChat[i].extra?.reasoning_duration, - ), + mes: isOtherGroupMember + ? coreChat[i].mes + : promptReasoning.addToMessage( + coreChat[i].mes, + regexedReasoning[i], + isPrefix, + coreChat[i].extra?.reasoning_duration, + ), }; if (promptReasoning.isLimitReached()) { break; @@ -5064,8 +5156,7 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr if (main_api == 'koboldhorde' && (horde_settings.auto_adjust_context_length || horde_settings.auto_adjust_response_length)) { try { adjustedParams = await adjustHordeGenerationParams(max_context, amount_gen); - } - catch { + } catch { unblockGeneration(type); return Promise.resolve(); } @@ -5251,8 +5342,7 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr // When continuing generation of previous output, last user message precedes the message to continue if (isContinue) { coreChat.splice(coreChat.length - 1, 0, { mes: jailbreak, is_user: true }); - } - else { + } else { // This operation will result in the injectedIndices indexes being off by one coreChat.push({ mes: jailbreak, is_user: true }); // Add +1 to the elements to correct for the new PHI/Jailbreak message. @@ -5283,7 +5373,7 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr chat2[i] = formatMessageHistoryItem(coreChat[j], isInstruct, force_output_sequence.FIRST); } - if (lastUserMessageIndex >= 0 && j === lastUserMessageIndex && isInstruct) { + if (lastUserMessageIndex >= 0 && j === lastUserMessageIndex && isInstruct && !isImpersonate) { // Reformat with the last input sequence (if any) chat2[i] = formatMessageHistoryItem(coreChat[j], isInstruct, force_output_sequence.LAST); } @@ -5531,7 +5621,6 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr // Add quiet generation prompt at depth 0 if (quiet_prompt && quiet_prompt.length) { - // here name1 is forced for all quiet prompts..why? const name = name1; //checks if we are in instruct, if so, formats the chat as such, otherwise just adds the quiet prompt @@ -5899,7 +5988,7 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr streamingProcessor.firstMessageText = ''; } - streamingProcessor.generator = await sendStreamingRequest(type, generate_data); + streamingProcessor.generator = await sendStreamingRequest(type, generate_data, { jsonSchema }); hideSwipeButtons(); let getMessage = await streamingProcessor.generate(); @@ -5921,9 +6010,14 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr const hasToolCalls = ToolManager.hasToolCalls(streamingProcessor.toolCalls); const shouldDeleteMessage = type !== 'swipe' && ['', '...'].includes(lastMessage?.mes) && !lastMessage?.extra?.reasoning && ['', '...'].includes(streamingProcessor?.result); hasToolCalls && shouldDeleteMessage && await deleteLastMessage(); - const invocationResult = await ToolManager.invokeFunctionTools(streamingProcessor.toolCalls); const native = streamingProcessor?.native ?? null; const reasoningContent = streamingProcessor?.reasoningHandler?.reasoning || null; + if (hasToolCalls && !shouldDeleteMessage) { + await streamingProcessor.finalizeIntermediaryMessage(streamingProcessor.messageId, getMessage, { unlockUI: false }); + } + const invocationResult = await ToolManager.invokeFunctionTools(streamingProcessor.toolCalls, { + reasoningText: reasoningContent, + }); const shouldStopGeneration = (!invocationResult.invocations.length && shouldDeleteMessage) || invocationResult.stealthCalls.length; if (hasToolCalls) { if (shouldStopGeneration) { @@ -5985,7 +6079,7 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr if (jsonSchema) { unblockGeneration(type); - return extractJsonFromData(data); + return extractJsonFromData(data, { returnInvalidJson: jsonSchema.returnInvalid ?? false }); } //const getData = await response.json(); @@ -6031,17 +6125,14 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr if (isImpersonate) { $('#send_textarea').val(getMessage)[0].dispatchEvent(new Event('input', { bubbles: true })); await eventSource.emit(event_types.IMPERSONATE_READY, getMessage); - } - else if (type == 'quiet') { + } else if (type == 'quiet') { unblockGeneration(type); return getMessage; - } - else { + } else { // Without streaming we'll be having a full message on continuation. Treat it as a last chunk. if (originalType !== 'continue') { ({ type, getMessage } = await saveReply({ type, getMessage, title, swipes, reasoning, imageUrls, reasoningSignature, native })); - } - else { + } else { ({ type, getMessage } = await saveReply({ type: 'appendFinal', getMessage, title, swipes, reasoning, imageUrls, reasoningSignature, native })); } @@ -6053,7 +6144,7 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr const hasToolCalls = ToolManager.hasToolCalls(data); const shouldDeleteMessage = type !== 'swipe' && ['', '...'].includes(getMessage) && !reasoning; hasToolCalls && shouldDeleteMessage && await deleteLastMessage(); - const invocationResult = await ToolManager.invokeFunctionTools(data); + const invocationResult = await ToolManager.invokeFunctionTools(data, { reasoningText: reasoning }); const shouldStopGeneration = (!invocationResult.invocations.length && shouldDeleteMessage) || invocationResult.stealthCalls.length; if (hasToolCalls) { if (shouldStopGeneration) { @@ -6078,7 +6169,6 @@ async function GenerateInternal(type, { automatic_trigger, force_name2, quiet_pr if (!isAborted && power_user.auto_swipe && generatedTextFiltered(getMessage)) { is_send_press = false; return await swipe(null, SWIPE_DIRECTION.RIGHT, { source: SWIPE_SOURCE.AUTO_SWIPE, repeated: true, forceMesId: chat.length - 1 }); - } console.debug('/api/chats/save called by /Generate'); @@ -6568,32 +6658,26 @@ export async function sendMessageAsUser(messageText, messageBias, insertAt = nul await eventSource.emit(event_types.USER_MESSAGE_RENDERED, insertAt); } else { chat.push(message); + await saveChatConditional(); const chat_id = (chat.length - 1); await eventSource.emit(event_types.MESSAGE_SENT, chat_id); addOneMessage(message); await eventSource.emit(event_types.USER_MESSAGE_RENDERED, chat_id); - await saveChatConditional(); } return message; } /** - * Gets the maximum usable context size for the current API. - * @param {number|null} overrideResponseLength Optional override for the response length. - * @returns {number} Maximum usable context size. + * Gets the maximum context token limit (the full context window size before subtracting response length). + * @returns {number} The maximum context token limit for the current API. */ -export function getMaxContextSize(overrideResponseLength = null) { - if (typeof overrideResponseLength !== 'number' || overrideResponseLength <= 0 || isNaN(overrideResponseLength)) { - overrideResponseLength = null; - } - - let this_max_context = 1487; +export function getMaxContextTokens() { if (main_api == 'kobold' || main_api == 'koboldhorde' || main_api == 'textgenerationwebui') { - this_max_context = (max_context - (overrideResponseLength || amount_gen)); + return max_context; } if (main_api == 'novel') { - this_max_context = Number(max_context); + let this_max_context = Number(max_context); if (nai_settings.model_novel.includes('clio')) { this_max_context = Math.min(max_context, 8192); } @@ -6613,13 +6697,39 @@ export function getMaxContextSize(overrideResponseLength = null) { // Added special tokens and whatnot this_max_context -= 10; } - - this_max_context = this_max_context - (overrideResponseLength || amount_gen); + return this_max_context; } if (main_api == 'openai') { - this_max_context = oai_settings.openai_max_context - (overrideResponseLength || oai_settings.openai_max_tokens); + return oai_settings.openai_max_context; } - return this_max_context; + return 1487; +} + +/** + * Gets the maximum response token limit (the max generation/reply length). + * @returns {number} The maximum response token limit for the current API. + */ +export function getMaxResponseTokens() { + if (main_api == 'kobold' || main_api == 'koboldhorde' || main_api == 'textgenerationwebui' || main_api == 'novel') { + return amount_gen; + } + if (main_api == 'openai') { + return oai_settings.openai_max_tokens; + } + return 0; +} + +/** + * Gets the maximum usable prompt size for the current API. + * @param {number|null} overrideResponseLength Optional override for the response length. + * @returns {number} Maximum usable prompt size. + */ +export function getMaxPromptTokens(overrideResponseLength = null) { + if (typeof overrideResponseLength !== 'number' || overrideResponseLength <= 0 || isNaN(overrideResponseLength)) { + overrideResponseLength = null; + } + + return getMaxContextTokens() - (overrideResponseLength || getMaxResponseTokens()); } function parseTokenCounts(counts, thisPromptBits) { @@ -6655,41 +6765,65 @@ function addChatsPreamble(mesSendString) { function addChatsSeparator(mesSendString) { if (power_user.context.chat_start) { return substituteParams(power_user.context.chat_start + '\n') + mesSendString; - } - - else { + } else { return mesSendString; } } -export async function duplicateCharacter() { - if (this_chid === undefined || !characters[this_chid]) { - toastr.warning(t`You must first select a character to duplicate!`); - return ''; +/** + * Duplicates a character. + * @param {object} [options={}] - Options + * @param {string} [options.avatar] - Avatar key of the character to duplicate. Uses current character if not provided. + * @param {boolean} [options.silent=false] - Whether to skip the confirmation popup + * @returns {Promise} The avatar key of the duplicated character, or empty string if cancelled/failed + */ +export async function duplicateCharacter({ avatar = null, silent = false } = {}) { + // Determine the character to duplicate + let targetAvatar; + if (avatar) { + const character = characters.find(c => c.avatar === avatar); + if (!character) { + toastr.warning(t`Character not found: ${avatar}`); + return ''; + } + targetAvatar = avatar; + } else { + if (this_chid === undefined || !characters[this_chid]) { + toastr.warning(t`You must first select a character to duplicate!`); + return ''; + } + targetAvatar = characters[this_chid].avatar; } - const confirmMessage = $(await renderTemplateAsync('duplicateConfirm')); - const confirm = await callGenericPopup(confirmMessage, POPUP_TYPE.CONFIRM); + // Show confirmation unless silent + if (!silent) { + const confirmMessage = $(await renderTemplateAsync('duplicateConfirm')); + const confirm = await callGenericPopup(confirmMessage, POPUP_TYPE.CONFIRM); - if (!confirm) { - console.log('User cancelled duplication'); - return ''; + if (!confirm) { + console.log('User cancelled duplication'); + return ''; + } } - const body = { avatar_url: characters[this_chid].avatar }; + const body = { avatar_url: targetAvatar }; const response = await fetch('/api/characters/duplicate', { method: 'POST', headers: getRequestHeaders(), body: JSON.stringify(body), }); - if (response.ok) { - toastr.success(t`Character Duplicated`); - const data = await response.json(); - await eventSource.emit(event_types.CHARACTER_DUPLICATED, { oldAvatar: body.avatar_url, newAvatar: data.path }); - await getCharacters(); + + if (!response.ok) { + toastr.error(t`Failed to duplicate character`); + return ''; } - return ''; + toastr.success(t`Character Duplicated`); + const data = await response.json(); + await eventSource.emit(event_types.CHARACTER_DUPLICATED, { oldAvatar: targetAvatar, newAvatar: data.path }); + await getCharacters(); + + return data.path; } function setInContextMessages(msgInContextCount, type) { @@ -6704,7 +6838,7 @@ function setInContextMessages(msgInContextCount, type) { if (lastMessageBlock.length === 0) { const firstMessageId = getFirstDisplayedMessageId(); - chatElement.find(`.mes[mesid="${firstMessageId}"`).addClass('lastInContext'); + chatElement.find(`.mes[mesid="${firstMessageId}"]`).addClass('lastInContext'); } // Update last id to chat. No metadata save on purpose, gets hopefully saved via another call @@ -6901,7 +7035,7 @@ export function extractMessageFromData(data, activeApi = null) { case 'novel': return data.output; case 'openai': - return data?.content?.find(p => p.type === 'text')?.text ?? data?.choices?.[0]?.message?.content ?? data?.choices?.[0]?.text ?? data?.text ?? data?.message?.content?.[0]?.text ?? data?.message?.tool_plan ?? ''; + return data?.content?.filter(p => p.type === 'text')?.map(p => p.text)?.join('\n\n') ?? data?.choices?.[0]?.message?.content ?? data?.choices?.[0]?.text ?? data?.text ?? data?.message?.content?.[0]?.text ?? data?.message?.tool_plan ?? ''; default: return ''; } @@ -6914,9 +7048,13 @@ export function extractMessageFromData(data, activeApi = null) { /** * Extracts JSON from the response data. * @param {object} data Response data + * @param {object} [options] Extraction options + * @param {string} [options.mainApi] Main API to use + * @param {string} [options.chatCompletionSource] Chat completion source + * @param {boolean} [options.returnInvalidJson=false] Whether to return the raw JSON string even if it fails to parse * @returns {string} Extracted JSON string from the response data */ -export function extractJsonFromData(data, { mainApi = null, chatCompletionSource = null } = {}) { +export function extractJsonFromData(data, { mainApi = null, chatCompletionSource = null, returnInvalidJson = false } = {}) { mainApi = mainApi ?? main_api; chatCompletionSource = chatCompletionSource ?? oai_settings.chat_completion_source; @@ -6939,6 +7077,9 @@ export function extractJsonFromData(data, { mainApi = null, chatCompletionSource break; case chat_completion_sources.PERPLEXITY: result = tryParse(removeReasoningFromString(text)); + if (!result && returnInvalidJson) { + return text; + } break; case chat_completion_sources.VERTEXAI: case chat_completion_sources.MAKERSUITE: @@ -6959,6 +7100,9 @@ export function extractJsonFromData(data, { mainApi = null, chatCompletionSource case chat_completion_sources.ZAI: default: result = tryParse(text); + if (!result && returnInvalidJson) { + return text; + } break; } } break; @@ -7065,7 +7209,7 @@ export function cleanUpMessage({ getMessage, isImpersonate, isContinue, displayI // Allow for caching of stopping strings. getStoppingStrings is an expensive function, especially with macros // enabled, so for streaming, we call it once and then pass it into each cleanUpMessage call. if (!stoppingStrings) { - stoppingStrings = getStoppingStrings(isImpersonate, isContinue); + stoppingStrings = getStoppingStrings(isImpersonate, isContinue, main_api); } for (const stoppingString of stoppingStrings) { @@ -7350,7 +7494,6 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type); addOneMessage(chat[chat_id], { type: 'swipe' }); !fromStreaming && await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type); - } else { console.debug('entering chat update routine for non-swipe post'); const newMessage = {}; @@ -7564,20 +7707,24 @@ export function syncMesToSwipe(messageId = null) { * If the swipe data is invalid in some way, this function will exit out without doing anything. * @param {number?} [messageId=null] - The ID of the message to sync with the swipe data. If no ID is given, the last message is used. * @param {number?} [swipeId=null] - The ID of the swipe to sync. If no ID is given, the current swipe ID in the message object is used. + * @param {ChatMessage?} [targetMessage=null] - The message object to sync instead of resolving one from `chat`. * @returns {boolean} Whether the swipe data was successfully synced to the message */ -export function syncSwipeToMes(messageId = null, swipeId = null) { - if (!chat.length) { +export function syncSwipeToMes(messageId = null, swipeId = null, targetMessage = null) { + if (!targetMessage && !chat.length) { return false; } - const targetMessageId = messageId ?? chat.length - 1; - if (targetMessageId >= chat.length || targetMessageId < 0) { - console.warn(`[syncSwipeToMes] Invalid message ID: ${messageId}`); - return false; + if (!targetMessage) { + const targetMessageId = messageId ?? chat.length - 1; + if (targetMessageId >= chat.length || targetMessageId < 0) { + console.warn(`[syncSwipeToMes] Invalid message ID: ${messageId}`); + return false; + } + + targetMessage = chat[targetMessageId]; } - const targetMessage = chat[targetMessageId]; if (!targetMessage) { return false; } @@ -7895,16 +8042,13 @@ export async function renameCharacter(name = null, { silent = false, renameChats } else { toastr.success(t`Character renamed!`, t`Rename Character`); } - } - else { + } else { throw new Error('Newly renamed character was lost?'); } - } - else { + } else { throw new Error('Could not rename the character'); } - } - catch (error) { + } catch (error) { // Reloading to prevent data corruption if (!silent) await Popup.show.text(t`Rename Character`, t`Something went wrong. The page will be reloaded.`); else toastr.error(t`Something went wrong. The page will be reloaded.`, t`Rename Character`); @@ -7970,7 +8114,7 @@ async function renamePastChats(oldAvatar, newAvatar, newName) { payload: currentChat, }); } else { - const saveChatResponse = await fetch('/api/chats/save', { + const saveChatRequest = await compressRequest({ method: 'POST', headers: getRequestHeaders(), body: JSON.stringify({ @@ -7981,6 +8125,7 @@ async function renamePastChats(oldAvatar, newAvatar, newName) { }), cache: 'no-cache', }); + const saveChatResponse = await fetch('/api/chats/save', saveChatRequest); if (!saveChatResponse.ok) { throw new Error('Could not save chat'); @@ -8040,6 +8185,7 @@ export function markWindowedChatDirtyFromIndex(messageId) { * @param {object} [options.withMetadata] Additional metadata to save with the chat * @param {number} [options.mesId] The message ID to save the chat up to * @param {boolean} [options.force] Force the saving despite the integrity check result + * @param {ChatMessage[]} [options.chatData] Chat snapshot to save instead of the current in-memory chat * * @returns {Promise} */ @@ -8052,7 +8198,7 @@ export async function saveChat(...args) { return enqueueChatSave(() => saveChatUnsafe(...args)); } -async function saveChatUnsafe({ chatName, withMetadata, mesId, force = false } = {}) { +async function saveChatUnsafe({ chatName, withMetadata, mesId, force = false, chatData = undefined } = {}) { if (arguments.length > 0 && typeof arguments[0] !== 'object') { console.trace('saveChat called with positional arguments. Please use an object instead.'); [chatName, withMetadata, mesId, force] = arguments; @@ -8074,9 +8220,11 @@ async function saveChatUnsafe({ chatName, withMetadata, mesId, force = false } = characters[this_chid].date_last_chat = Date.now(); - const trimmedChat = (mesId !== undefined && mesId >= 0 && mesId < chat.length) - ? chat.slice(0, Number(mesId) + 1) - : chat.slice(); + const trimmedChat = Array.isArray(chatData) + ? chatData + : (mesId !== undefined && mesId >= 0 && mesId < chat.length) + ? chat.slice(0, Number(mesId) + 1) + : chat.slice(); /** @type {ChatHeader} */ const chatHeader = { @@ -8085,53 +8233,50 @@ async function saveChatUnsafe({ chatName, withMetadata, mesId, force = false } = character_name: 'unused', }; const payload = [chatHeader, ...trimmedChat]; - const isIntegrityTransportError = (error) => - String(error?.code || '').toLowerCase() === 'integrity' - || /integrity/i.test(String(error?.message || '')); - try { - if (isTauriChatPayloadTransportEnabled()) { - const windowState = getWindowedChatState(); - if (windowState?.kind === 'character' && windowState.cursor && windowState.fileName === fileName) { - const expectedWindowKey = getWindowedChatKey(windowState); - const expectedCursorOffset = windowState.cursor.offset; - const { - patch, - savedMessageCount: nextSavedMessageCount, - dirtyFromIndex: nextDirtyFromIndex, - } = buildWindowedPayloadPatch(trimmedChat, windowState, 'chat'); + try { + if (isTauriChatPayloadTransportEnabled()) { + const windowState = getWindowedChatState(); + if (windowState?.kind === 'character' && windowState.cursor && windowState.fileName === fileName) { + const expectedWindowKey = getWindowedChatKey(windowState); + const expectedCursorOffset = windowState.cursor.offset; + const { + patch, + savedMessageCount: nextSavedMessageCount, + dirtyFromIndex: nextDirtyFromIndex, + } = buildWindowedPayloadPatch(trimmedChat, windowState, 'chat'); const cursor = await patchCharacterChatPayloadWindowed({ characterName: characters[this_chid].name, avatarUrl: characters[this_chid].avatar, - fileName: fileName, + fileName, cursor: windowState.cursor, header: JSON.stringify(chatHeader), - patch, - force: Boolean(force), - }); + patch, + force: Boolean(force), + }); - const activeWindowState = getWindowedChatState(); - if (getWindowedChatKey(activeWindowState) === expectedWindowKey) { - const shouldUpdateCounters = activeWindowState?.cursor?.offset === expectedCursorOffset; - const mergedCursor = mergeWindowedChatCursorOffset(activeWindowState?.cursor, cursor, expectedCursorOffset); - const nextWindowState = { - ...activeWindowState, - cursor: mergedCursor, - }; + const activeWindowState = getWindowedChatState(); + if (getWindowedChatKey(activeWindowState) === expectedWindowKey) { + const shouldUpdateCounters = activeWindowState?.cursor?.offset === expectedCursorOffset; + const mergedCursor = mergeWindowedChatCursorOffset(activeWindowState?.cursor, cursor, expectedCursorOffset); + const nextWindowState = { + ...activeWindowState, + cursor: mergedCursor, + }; - if (shouldUpdateCounters) { - nextWindowState.savedMessageCount = nextSavedMessageCount; - nextWindowState.dirtyFromIndex = nextDirtyFromIndex; - } + if (shouldUpdateCounters) { + nextWindowState.savedMessageCount = nextSavedMessageCount; + nextWindowState.dirtyFromIndex = nextDirtyFromIndex; + } - setWindowedChatState(nextWindowState); - } - } else { - await saveCharacterChatPayload({ - characterName: characters[this_chid].name, - avatarUrl: characters[this_chid].avatar, - fileName: fileName, + setWindowedChatState(nextWindowState); + } + } else { + await saveCharacterChatPayload({ + characterName: characters[this_chid].name, + avatarUrl: characters[this_chid].avatar, + fileName, payload, force: Boolean(force), }); @@ -8139,7 +8284,7 @@ async function saveChatUnsafe({ chatName, withMetadata, mesId, force = false } = return; } - const result = await fetch('/api/chats/save', { + const saveChatRequest = await compressRequest({ method: 'POST', cache: 'no-cache', headers: getRequestHeaders(), @@ -8151,6 +8296,7 @@ async function saveChatUnsafe({ chatName, withMetadata, mesId, force = false } = force: force, }), }); + const result = await fetch('/api/chats/save', saveChatRequest); if (result.ok) { return; @@ -8165,7 +8311,10 @@ async function saveChatUnsafe({ chatName, withMetadata, mesId, force = false } = } throw new Error(result.statusText); } catch (error) { - const isIntegrityError = isIntegrityTransportError(error) && !force; + const isIntegrityError = ( + String(error?.code || '').toLowerCase() === 'integrity' + || /integrity/i.test(String(error?.message || '')) + ) && !force; if (!isIntegrityError) { console.error(error); toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Chat could not be saved`); @@ -8226,29 +8375,26 @@ async function read_avatar_load(input) { } await createOrEditCharacter(); - await delay(DEFAULT_SAVE_EDIT_TIMEOUT); const formData = new FormData(/** @type {HTMLFormElement} */($('#form_create').get(0))); - await fetch(getThumbnailUrl('avatar', formData.get('avatar_url').toString(), true), { - method: 'GET', - cache: 'reload', - }); + const avatarKey = formData.get('avatar_url').toString(); - const messages = $('.mes').toArray(); - for (const el of messages) { - const $el = $(el); - const nameMatch = $el.attr('ch_name') == formData.get('ch_name'); - if ($el.attr('is_system') == 'true' && !nameMatch) continue; - if ($el.attr('is_user') == 'true') continue; + // Bust cache for the avatar thumbnail and character image + const thumbnailUrl = getThumbnailUrl('avatar', avatarKey); + await fetch(getThumbnailUrl('avatar', avatarKey, true), { method: 'GET', cache: 'reload' }); + await fetch(`/characters/${avatarKey}`, { method: 'GET', cache: 'reload' }); - if (nameMatch) { - const previewSrc = $('#avatar_load_preview').attr('src'); - const avatar = $el.find('.avatar img'); - avatar.attr('src', default_avatar); - await delay(1); - avatar.attr('src', previewSrc); + // Refresh all visible avatar images that use this thumbnail URL + // This handles messages, character list, and any other place using the thumbnail + const avatarImages = document.querySelectorAll(`img[src^="${thumbnailUrl}"]`); + for (const img of avatarImages) { + if (img instanceof HTMLImageElement) { + const originalSrc = img.src; + img.src = ''; + img.src = originalSrc; } } + console.debug(`Refreshed ${avatarImages.length} avatar images for ${avatarKey}`); console.log('Avatar refreshed'); } @@ -8307,8 +8453,7 @@ export function buildAvatarList(block, entities, { templateId = 'inline_avatar_t avatarTemplate.append(grpTemplate.children()); avatarTemplate.attr({ 'data-grid': id, 'data-chid': null }); avatarTemplate.attr('title', `[Group] ${entity.item.name}`); - } - else if (entity.type === 'persona') { + } else if (entity.type === 'persona') { avatarTemplate.attr({ 'data-pid': id, 'data-chid': null }); avatarTemplate.find('img').attr('src', getThumbnailUrl('persona', entity.item.avatar)); avatarTemplate.attr('title', `[Persona] ${entity.item.name}\nFile: ${entity.item.avatar}`); @@ -8692,7 +8837,7 @@ function reloadLoop() { } } -async function applySettingsSnapshot(data) { +async function applySettingsSnapshot(data, initLoaderHandle = null) { if (data.result != 'file not find' && data.settings) { settings = JSON.parse(data.settings); if (settings.username !== undefined && settings.username !== '') { @@ -8702,6 +8847,7 @@ async function applySettingsSnapshot(data) { accountStorage.init(settings?.accountStorage); await setUserControls(data.enable_accounts); + setRequestCompressionConfig(data.request_compression); // Allow subscribers to mutate settings await eventSource.emit(event_types.SETTINGS_LOADED_BEFORE, settings); @@ -8793,12 +8939,25 @@ async function applySettingsSnapshot(data) { if (data.enable_extensions) { applyExtensionSettings(settings); + } else { + Object.assign(extension_settings, (settings.extension_settings ?? {})); + $('#third_party_extension_button').addClass('disabled'); + $('#extensions_details').addClass('disabled'); + $('#extensions_connect').addClass('disabled'); + $('#extensions_notify_updates').attr('disabled', 'disabled'); + $('#extensions_autoconnect').attr('disabled', 'disabled'); + $('#extensions_url').attr('disabled', 'disabled'); + $('#extensions_api_key').attr('disabled', 'disabled'); } firstRun = !!settings.firstRun; if (firstRun) { - hideLoader(); + if (initLoaderHandle) { + await initLoaderHandle.hide(); + } else { + hideLoader(); + } await doOnboarding(user_avatar); firstRun = false; } @@ -8810,7 +8969,7 @@ async function applySettingsSnapshot(data) { //MARK: getSettings() /////////////////////////////////////////// -export async function getSettings() { +export async function getSettings(initLoaderHandle = null) { const response = await fetch('/api/settings/get', { method: 'POST', headers: getRequestHeaders(), @@ -8825,7 +8984,7 @@ export async function getSettings() { } const data = await response.json(); - await applySettingsSnapshot(data); + await applySettingsSnapshot(data, initLoaderHandle); } //MARK: saveSettings() @@ -8875,12 +9034,13 @@ export async function saveSettings(loopCounter = 0) { }; try { - const result = await fetch('/api/settings/save', { + const saveSettingsRequest = await compressRequest({ method: 'POST', headers: getRequestHeaders(), body: JSON.stringify(payload), cache: 'no-cache', }); + const result = await fetch('/api/settings/save', saveSettingsRequest); if (!result.ok) { throw new Error(`Failed to save settings: ${result.statusText}`); @@ -9163,8 +9323,7 @@ async function messageEditCancel(messageId = this_edit_mes_id) { await eventSource.emit(event_types.MESSAGE_UPDATED, messageId); if (messageId == this_edit_mes_id) { this_edit_mes_id = undefined; - } - else { + } else { console.warn(`The message editor was closed on message #${messageId} while #${this_edit_mes_id} is being edited.`); } @@ -9198,8 +9357,7 @@ async function messageEditMove(sourceId, targetId) { if (sourceId <= targetId) { sourceMessageDiv.insertAfter(targetMessageDiv); - } - else { + } else { sourceMessageDiv.insertBefore(targetMessageDiv); } @@ -9356,7 +9514,6 @@ export async function getChatsFromFiles(data, isGroupChat) { currentChat.shift(); } chat_dict[file_name] = currentChat; - } catch (error) { console.error(error); } @@ -10015,7 +10172,22 @@ export async function updateSwipeCounter(mesId, { message = undefined, messageEl const swipeCounterText = formatSwipeCounter((message?.swipe_id + 1), message?.swipes?.length); const swipeCounter = messageElement.find('.swipes-counter'); - swipeCounter.text(swipeCounterText).prop('hidden', false); + const swipePickerButton = messageElement.find('.mes_swipe_picker'); + const canOpenSwipePicker = canOpenSwipePickerForMessage(mesId); + const canJumpToSwipe = canJumpToSwipeForMessage(mesId); + + swipeCounter + .text(swipeCounterText) + .prop('hidden', false) + .toggleClass('swipe-picker-enabled', canOpenSwipePicker) + .toggleClass(INTERACTABLE_CONTROL_CLASS, canOpenSwipePicker) + .attr('role', canOpenSwipePicker ? 'button' : null) + .attr('title', canJumpToSwipe ? t`Click to jump to a swipe` : canOpenSwipePicker ? t`Click to view swipe history` : null); + swipePickerButton.toggle(canOpenSwipePicker); + + if (!canOpenSwipePicker) { + swipeCounter.removeAttr('tabindex'); + } } /** @@ -10065,11 +10237,13 @@ export function isMessageSwipeable(messageId, message = undefined) { //User messages are not swipeable. !message.is_user ) - ) - //The message is swipeable. - { return true; } - //The message is not swipeable. - else { return false; } + ) { + // The message is swipeable. + return true; + } else { + // The message is not swipeable. + return false; + } } /** @@ -10142,6 +10316,8 @@ export function refreshSwipeButtons(updateCounters = false, fade = true) { const isLastSwipe = (message?.swipes?.length ?? 1) - 1 <= (message?.swipe_id ?? 0); const hasSwipes = (message?.swipes?.length > 1); const overswipe = getOverswipeBehavior(messageId, message); + const swipePickerButton = $(div).find('.mes_swipe_picker'); + const canOpenSwipePicker = canOpenSwipePickerForMessage(messageId); // Chevrons should always be shown on pristine greetings: https://github.com/SillyTavern/SillyTavern/pull/4712#issuecomment-3557893373 const pristineGreeting = overswipe == OVERSWIPE_BEHAVIOR.PRISTINE_GREETING; @@ -10155,12 +10331,14 @@ export function refreshSwipeButtons(updateCounters = false, fade = true) { //If there's only one swipe, the left arrow should not be shown. div.classList.toggle('swipes_visible', hasSwipes || pristineGreeting); + swipePickerButton.toggle(canOpenSwipePicker); //updateSwipeCounter does not need to be awaited, It can run a bit later. if (updateCounters) updateSwipeCounter(messageId, { message, messageElement: $(div) }); } else { //Hide all messages that are not swipeable. div.classList.remove('swipes_visible', 'last_swipe'); + $(div).find('.mes_swipe_picker').toggle(canOpenSwipePickerForMessage(messageId)); } }); } @@ -10194,9 +10372,12 @@ export function hideSwipeButtons({ hideCounters = false } = {}) { * @returns {Promise|undefined} - The ID of the new swipe after deletion. */ export async function deleteSwipe(swipeId = null, messageId = chat.length - 1) { - if (swipeId && (isNaN(swipeId) || swipeId < 0)) { - toastr.warning(t`Invalid swipe ID: ${swipeId + 1}`); - return; + if (swipeId != null) { + swipeId = Number(swipeId); + if (!Number.isInteger(swipeId) || swipeId < 0) { + toastr.warning(t`Invalid swipe ID.`); + return; + } } const message = chat[messageId]; @@ -10210,7 +10391,8 @@ export async function deleteSwipe(swipeId = null, messageId = chat.length - 1) { return; } - swipeId = swipeId ?? message.swipe_id; + swipeId = Number(swipeId ?? message.swipe_id); + const currentSwipeId = clamp(Number(message.swipe_id ?? 0), 0, message.swipes.length - 1); if (swipeId < 0 || swipeId >= message.swipes.length) { toastr.warning(t`Invalid swipe ID: ${swipeId + 1}`); @@ -10224,17 +10406,35 @@ export async function deleteSwipe(swipeId = null, messageId = chat.length - 1) { message.swipe_info.splice(swipeId, 1); } - // Select the next swipe, or the one before if it was the last one - const newSwipeId = Math.min(swipeId, message.swipes.length - 1); + let newSwipeId; + if (swipeId < currentSwipeId) { + newSwipeId = currentSwipeId - 1; + } else if (swipeId > currentSwipeId) { + newSwipeId = currentSwipeId; + } else { + // Select the next swipe, or the one before if it was the last one. + newSwipeId = Math.min(swipeId, message.swipes.length - 1); + } chat_metadata.tainted = true; messageId = Number(messageId); swipeId = Number(swipeId); + message.swipe_id = newSwipeId; await eventSource.emit(event_types.MESSAGE_SWIPE_DELETED, { messageId, swipeId, newSwipeId }); - let direction = (swipeId <= newSwipeId) ? SWIPE_DIRECTION.RIGHT : SWIPE_DIRECTION.LEFT; - //Animate swipe and swap dispayed message. - await swipe(null, direction, { source: SWIPE_SOURCE.DELETE, repeated: false, forceMesId: messageId, forceSwipeId: newSwipeId }); + + if (swipeId === currentSwipeId) { + const direction = (swipeId <= newSwipeId) ? SWIPE_DIRECTION.RIGHT : SWIPE_DIRECTION.LEFT; + // Animate swipe and swap displayed message when the currently visible swipe was deleted. + await swipe(null, direction, { source: SWIPE_SOURCE.DELETE, repeated: false, forceMesId: messageId, forceSwipeId: newSwipeId }); + } else { + await updateSwipeCounter(messageId); + if (messageId !== chat.length - 1) { + await updateSwipeCounter(chat.length - 1); + } + refreshSwipeButtons(); + saveChatDebounced(); + } await saveChatConditional(); await pruneAgentPersistentStatesAfterDeletion(deletedAgentStateIds); @@ -10361,8 +10561,7 @@ export function closeMessageEditor(what = 'all') { export function setGenerationProgress(progress) { if (!progress) { $('#send_textarea').css({ 'background': '', 'transition': '' }); - } - else { + } else { $('#send_textarea').css({ 'background': `linear-gradient(90deg, #008000d6 ${progress}%, transparent ${progress}%)`, 'transition': '0.25s ease-in-out', @@ -10692,7 +10891,6 @@ export async function createOrEditCharacter(e) { select_rm_info('char_create', avatarId, oldSelectedChar); crop_data = undefined; - } catch (error) { console.error('Error creating character', error); toastr.error(t`Failed to create character`); @@ -10777,7 +10975,7 @@ function formatSwipeCounter(current, total) { * @param {SwipeEvent} event Event. * @param {SWIPE_DIRECTION} direction The direction to swipe. * @param {object} params Additional parameters. - * @param {import('./scripts/constants.js').SWIPE_SOURCE} [params.source] The source of the swipe event. null, 'keyboard', 'auto_swipe', 'back' or 'delete'. + * @param {import('./scripts/constants.js').SWIPE_SOURCE} [params.source] The source of the swipe event. * @param {boolean} [params.repeated] Is the swipe event repeated. * @param {ChatMessage} [params.message=chat[chat.length - 1]] The chat message to swipe. * @param {number} [params.forceMesId] The message id to swipe. @@ -10803,7 +11001,7 @@ export async function swipe(event, direction, { source, repeated, message = chat const mesId = Number(forceMesId ?? event?.currentTarget?.closest('.mes')?.getAttribute('mesid') ?? messageIndex ?? chat.length - 1); - if (source === SWIPE_SOURCE.DELETE || source === SWIPE_SOURCE.BACK || source === SWIPE_SOURCE.AUTO_SWIPE) { + if ([SWIPE_SOURCE.DELETE, SWIPE_SOURCE.BACK, SWIPE_SOURCE.AUTO_SWIPE, SWIPE_SOURCE.SLASH_COMMAND, SWIPE_SOURCE.SWIPE_PICKER].includes(source)) { console.info(`The ${direction} swipe source on message #${mesId} is ${source}, Most checks have been bypassed. `); } else { //Only show an error if swipes are not hidden and a message is generating. @@ -10877,8 +11075,7 @@ export async function swipe(event, direction, { source, repeated, message = chat document.body.dataset.swiping = 'true'; await generation; } - } - catch (error) { + } catch (error) { console.warn(`Swipe failed, Swiping back. ${error}`); } @@ -10914,8 +11111,7 @@ export async function swipe(event, direction, { source, repeated, message = chat //Update the chat. await loadFromSwipeId(mesId, chat[mesId].swipe_id); await redisplayChat({ startIndex: mesId }); - } - else { + } else { await Popup.show.confirm( t`ERROR: syncSwipeToMes has failed to revert the failed ${direction} swipe on message #${mesId}.`, t`

After you click OK, the chat will be reloaded to prevent data corruption.

`, @@ -11089,7 +11285,6 @@ export async function swipe(event, direction, { source, repeated, message = chat duration: 0, //used to be 100 //Disabled on Cohee's request. https://github.com/SillyTavern/SillyTavern/pull/4610/files#r2408731744 queue: false, progress: function (animation, progress, remainingMs) { - if (is_animation_scroll) chatElement.scrollTop(getMessageBottomHeight(thisMesDiv)); }, complete: function () { @@ -11106,7 +11301,6 @@ export async function swipe(event, direction, { source, repeated, message = chat * @param {boolean} [skipSwipeOut=false] */ async function animateSwipe(run_generate = false, skipSwipeOut = false) { - if (!skipSwipeOut) { //Swipe out. await animateSwipeTransition(mesId, { xEnd: `${swipeRange}px`, duration: swipeDuration }); @@ -11181,7 +11375,6 @@ export async function swipe(event, direction, { source, repeated, message = chat //If the swipe is not being deleted. if (source != SWIPE_SOURCE.DELETE && source != SWIPE_SOURCE.BACK) { - // Make sure ad-hoc changes to extras are saved before swiping away syncMesToSwipe(mesId); @@ -11225,9 +11418,8 @@ export async function swipe(event, direction, { source, repeated, message = chat } await standardSwipe(newSwipeId); return; - } - //If swiping right. - else if (direction === SWIPE_DIRECTION.RIGHT) { + } else if (direction === SWIPE_DIRECTION.RIGHT) { + //If swiping right. // make new slot in array if (forceSwipeId == null) newSwipeId++; @@ -11254,18 +11446,16 @@ export async function swipe(event, direction, { source, repeated, message = chat chat[mesId].swipe_id = originalSwipeId; await endSwipe(); return; - } - //Regenerate the message - else if (overswipe == OVERSWIPE_BEHAVIOR.REGENERATE) { + } else if (overswipe == OVERSWIPE_BEHAVIOR.REGENERATE) { + //Regenerate the message clearMessageData(chat[mesId]); let run_generate = true; //Generate. await animateSwipe(run_generate); await endSwipe(); return; - } - // Loop to the first swipe. - else if (overswipe == OVERSWIPE_BEHAVIOR.LOOP || overswipe == OVERSWIPE_BEHAVIOR.PRISTINE_GREETING) { + } else if (overswipe == OVERSWIPE_BEHAVIOR.LOOP || overswipe == OVERSWIPE_BEHAVIOR.PRISTINE_GREETING) { + // Loop to the first swipe. newSwipeId = 0; } } @@ -11279,7 +11469,7 @@ export async function swipe(event, direction, { source, repeated, message = chat * Handles the swipe to the left event. * @param {SwipeEvent} [event] Event. * @param {object} params Additional parameters. - * @param {import('./scripts/constants.js').SWIPE_SOURCE} [params.source] The source of the swipe event. null, 'keyboard', 'auto_swipe', 'back' or 'delete'. + * @param {import('./scripts/constants.js').SWIPE_SOURCE} [params.source] The source of the swipe event. * @param {boolean} [params.repeated] Is the swipe event repeated. * @param {object} [params.message] The chat message to swipe. */ @@ -11292,7 +11482,7 @@ export async function swipe_left(event, { source, repeated, message } = {}) { * Handles the swipe to the right event. * @param {SwipeEvent} [event] Event. * @param {object} params Additional parameters. - * @param {import('./scripts/constants.js').SWIPE_SOURCE} [params.source] The source of the swipe event. null, 'keyboard', 'auto_swipe', 'back' or 'delete'. + * @param {import('./scripts/constants.js').SWIPE_SOURCE} [params.source] The source of the swipe event. * @param {boolean} [params.repeated] Is the swipe event repeated. * @param {object} [params.message] The chat message to swipe. */ @@ -11552,8 +11742,7 @@ export async function doNewChat({ deleteCurrentChat = false } = {}) { if (selected_group) { await createNewGroupChat(selected_group); if (deleteCurrentChat) await deleteGroupChat(selected_group, chat_file_for_del, { jumpToNewChat: false }); // don't jump, new chat was already created and jumped to above - } - else { + } else { //RossAscends: added character name to new chat filenames and replaced Date.now() with humanizedDateTime; chat_metadata = {}; characters[this_chid].chat = `${name2} - ${humanizedDateTime()}`; @@ -11562,7 +11751,6 @@ export async function doNewChat({ deleteCurrentChat = false } = {}) { await createOrEditCharacter(new CustomEvent('newChat')); if (deleteCurrentChat) await delChat(chat_file_for_del + '.jsonl'); } - } /** @@ -11574,7 +11762,7 @@ export async function doNewChat({ deleteCurrentChat = false } = {}) { * @param {string} param.newFileName New name for the chat (no JSONL extension) * @param {boolean} [param.loader=true] Whether to show loader during the operation */ -export async function renameGroupOrCharacterChat({ characterId, groupId, oldFileName, newFileName, loader }) { +export async function renameGroupOrCharacterChat({ characterId, groupId, oldFileName, newFileName, loader: showLoader }) { const currentChatId = getCurrentChatId(); const body = { is_group: !!groupId, @@ -11592,9 +11780,14 @@ export async function renameGroupOrCharacterChat({ characterId, groupId, oldFile return; } - try { - loader && showLoader(); + const loaderHandle = showLoader ? loader.show({ + slug: 'chat-rename', + title: t`Rename Chat`, + message: t`Renaming chat…`, + toastMode: loader.ToastMode.STATIC, + }) : null; + try { const response = await fetch('/api/chats/rename', { method: 'POST', body: JSON.stringify(body), @@ -11617,8 +11810,7 @@ export async function renameGroupOrCharacterChat({ characterId, groupId, oldFile if (groupId) { await renameGroupChat(groupId, oldFileName, newFileName); - } - else if (characterId !== undefined && String(characterId) === String(this_chid) && characters[characterId]?.chat === oldFileName) { + } else if (characterId !== undefined && String(characterId) === String(this_chid) && characters[characterId]?.chat === oldFileName) { characters[characterId].chat = newFileName; $('#selected_chat_pole').val(characters[characterId].chat); await createOrEditCharacter(); @@ -11627,12 +11819,14 @@ export async function renameGroupOrCharacterChat({ characterId, groupId, oldFile if (currentChatId) { await reloadCurrentChat(); } + + const eventData = { avatarId: body.avatar_url, groupId, oldFileName: body.original_file, newFileName: body.renamed_file }; + await eventSource.emit(event_types.CHAT_RENAMED, eventData); } catch { - loader && hideLoader(); await delay(500); await callGenericPopup('An error has occurred. Chat was not renamed.', POPUP_TYPE.TEXT); } finally { - loader && hideLoader(); + await loaderHandle?.hide(); } } @@ -11736,7 +11930,7 @@ export async function handleDeleteCharacter(this_chid, delete_chats) { * @param {string|string[]} characterKey - The key (avatar) of the character to be deleted * @param {Object} [options] - Optional parameters for the deletion * @param {boolean} [options.deleteChats=true] - Whether to delete associated chats or not - * @return {Promise} - A promise that resolves when the character is successfully deleted + * @return {Promise} - A promise that resolves when the character is successfully deleted */ export async function deleteCharacter(characterKey, { deleteChats = true } = {}) { if (!Array.isArray(characterKey)) { @@ -11750,16 +11944,17 @@ export async function deleteCharacter(characterKey, { deleteChats = true } = {}) t`Deleting this character will close the chat and you will lose any unsaved messages. Do you want to proceed?`, ); if (!confirmClose) { - return; + return false; } } const closeChatResult = await closeCurrentChat(); if (!closeChatResult) { - return; + return false; } const worldsToDelete = new Set(); + let deleted = false; for (const key of characterKey) { const character = characters.find(x => x.avatar == key); @@ -11829,6 +12024,7 @@ export async function deleteCharacter(characterKey, { deleteChats = true } = {}) } await eventSource.emit(event_types.CHARACTER_DELETED, { id: chid, character: character }); + deleted = true; } await removeCharacterFromUI(); @@ -11848,6 +12044,8 @@ export async function deleteCharacter(characterKey, { deleteChats = true } = {}) toastr.error(t`Failed to delete linked worldbook.`, t`Character Deleted`); } } + + return deleted; } /** @@ -12213,21 +12411,33 @@ jQuery(async function () { async function handleDeleteChat(chatFile, group, fromSlashCommand = false) { // Close past chat popup. $('#select_chat_cross').trigger('click'); - showLoader(); - if (group) { - await deleteGroupChat(group, chatFile); - } else { - await delChat(`${chatFile}.jsonl`); + + const loaderHandle = loader.show({ + slug: 'chat-delete', + title: t`Delete Chat`, + message: t`Deleting chat…`, + toastMode: loader.ToastMode.STATIC, + }); + + try { + if (group) { + await deleteGroupChat(group, chatFile); + } else { + await delChat(`${chatFile}.jsonl`); + } + } catch (error) { + loaderHandle.hide(); + throw error; } if (fromSlashCommand) { // When called from `/delchat` command, don't re-open the history view. $('#options').hide(); // Hide option popup menu. - hideLoader(); + await loaderHandle.hide(); } else { // Open the history view again after 2 seconds (delay to avoid edge cases for deleting last chat). - setTimeout(function () { + setTimeout(async function () { $('#option_select_chat').trigger('click'); $('#options').hide(); // Hide option popup menu. - hideLoader(); + await loaderHandle.hide(); }, 2000); } } @@ -12297,8 +12507,7 @@ jQuery(async function () { if (popup_type == 'input') { dialogueResolve($('#dialogue_popup_input').val()); $('#dialogue_popup_input').val(''); - } - else { + } else { dialogueResolve(true); } @@ -12532,9 +12741,7 @@ jQuery(async function () { }); } } - } - - else if (id == 'option_start_new_chat') { + } else if (id == 'option_start_new_chat') { if ((selected_group || this_chid !== undefined) && !is_send_press) { let deleteCurrentChat = false; const result = await Popup.show.confirm(t`Start new chat?`, await renderTemplateAsync('newChatConfirm'), { @@ -12550,9 +12757,7 @@ jQuery(async function () { const alreadyInTempChat = this_chid === undefined && name2 === neutralCharacterName; await newAssistantChat({ temporary: alreadyInTempChat }); } - } - - else if (id == 'option_regenerate') { + } else if (id == 'option_regenerate') { //Attempting to regenerate a user message will instead generate a new message. if (chat.length && chat.length - 1 === this_edit_mes_id && chat[this_edit_mes_id]?.is_user == false) { toastr.warning(t`Finish the edit before starting a generation.`, t`You cannot regenerate the message you are editing.`); @@ -12566,23 +12771,18 @@ jQuery(async function () { }); if (selected_group) { regenerateGroup(); - } - else { + } else { const generateOptions = buildOrFillAdditionalArgs(agentOptions); is_send_press = true; Generate('regenerate', generateOptions); } } - } - - else if (id == 'option_impersonate') { + } else if (id == 'option_impersonate') { if (is_send_press == false || fromSlashCommand) { is_send_press = true; Generate('impersonate', buildOrFillAdditionalArgs()); } - } - - else if (id == 'option_continue') { + } else if (id == 'option_continue') { if (swipeState == SWIPE_STATE.EDITING) { toastr.warning(t`Confirm the edit to start a generation.`, t`You cannot send a message during a swipe-edit.`); return; @@ -12596,24 +12796,16 @@ jQuery(async function () { is_send_press = true; Generate('continue', buildOrFillAdditionalArgs()); } - } - - else if (id == 'option_delete_mes') { + } else if (id == 'option_delete_mes') { setTimeout(() => openMessageDelete(fromSlashCommand), animation_duration); - } - - else if (id == 'option_close_chat') { + } else if (id == 'option_close_chat') { await closeCurrentChat(); - } - - else if (id === 'option_toggle_fullscreen') { + } else if (id === 'option_toggle_fullscreen') { const nextMode = !power_user.mobile_immersive_fullscreen; power_user.mobile_immersive_fullscreen = nextMode; setMobileImmersiveFullscreenEnabled(nextMode); saveSettingsDebounced(); - } - - else if (id === 'option_settings') { + } else if (id === 'option_settings') { //var checkBox = document.getElementById("waifuMode"); var topBar = document.getElementById('top-bar'); var topSettingsHolder = document.getElementById('top-settings-holder'); @@ -12626,9 +12818,7 @@ jQuery(async function () { divchat.style.borderRadius = ''; divchat.style.backgroundColor = ''; - } else { - divchat.style.borderRadius = '10px'; // Adjust the value to control the roundness of the corners divchat.style.backgroundColor = ''; // Set the background color to your preference @@ -13591,7 +13781,9 @@ jQuery(async function () { $('#avatar-and-name-block').slideToggle(); }); - $(document).on('mouseup touchend', '#show_more_messages', async function () { + $(document).on('click', '#show_more_messages', async function (event) { + event.stopPropagation(); + event.preventDefault(); await showMoreMessages(); }); diff --git a/src/scripts/BulkEditOverlay.js b/src/scripts/BulkEditOverlay.js index ef31f68a..a43780cc 100644 --- a/src/scripts/BulkEditOverlay.js +++ b/src/scripts/BulkEditOverlay.js @@ -14,10 +14,11 @@ import { } from '../script.js'; import { favsToHotswap } from './RossAscends-mods.js'; -import { hideLoader, showLoader } from './loader.js'; +import { loader } from './action-loader.js'; import { convertCharacterToPersona } from './personas.js'; import { callGenericPopup, POPUP_TYPE } from './popup.js'; import { createTagInput, getTagKeyForEntity, getTagsList, printTagList, tag_map, compareTagsForSort, removeTagFromMap, importTags, tag_import_setting } from './tags.js'; +import { t } from './i18n.js'; /** * Static object representing the actions of the @@ -101,7 +102,7 @@ class CharacterContextMenu { * @param {number} characterId * @returns {Promise} */ - static persona = async (characterId) => void(await convertCharacterToPersona(characterId)); + static persona = async (characterId) => void (await convertCharacterToPersona(characterId)); /** * Delete one or more characters, @@ -754,7 +755,7 @@ class BulkEditOverlay { handleContextMenuShow = (event) => { event.preventDefault(); - const [x,y] = this.#getContextMenuPosition(event); + const [x, y] = this.#getContextMenuPosition(event); CharacterContextMenu.show(x, y); this.#contextMenuOpen = true; }; @@ -846,15 +847,16 @@ class BulkEditOverlay { const deleteChats = checkbox.prop('checked') ?? false; - showLoader(); - const toast = toastr.info('We\'re deleting your characters, please wait...', 'Working on it'); + const loaderHandle = loader.show({ + slug: 'bulk-delete', + title: t`Bulk Delete`, + message: t`Deleting ${characterIds.length} character(s)…`, + toastMode: loader.ToastMode.STATIC, + }); const avatarList = characterIds.map(id => characters[id]?.avatar).filter(a => a); return CharacterContextMenu.delete(avatarList, deleteChats) .then(() => this.browseState()) - .finally(() => { - toastr.clear(toast); - hideLoader(); - }); + .finally(() => loaderHandle.hide()); }); // At this moment the popup is already changed in the dom, but not yet closed/resolved. We build the avatar list here diff --git a/src/scripts/a11y.js b/src/scripts/a11y.js index 78ebf898..888a857f 100644 --- a/src/scripts/a11y.js +++ b/src/scripts/a11y.js @@ -16,6 +16,7 @@ const buttonSelectors = [ '.jg-menu .jg-button', '.bg_example .mobile-only-menu-toggle', '.paginationjs-pages li a', + '#show_more_messages', ].join(', '); const listSelectors = [ diff --git a/src/scripts/action-loader-slashcommands.js b/src/scripts/action-loader-slashcommands.js new file mode 100644 index 00000000..278752c9 --- /dev/null +++ b/src/scripts/action-loader-slashcommands.js @@ -0,0 +1,370 @@ +import { ActionLoaderToastMode, getActiveLoaderHandles, getLoaderHandleById, loader } from './action-loader.js'; +import { t } from './i18n.js'; +import { SlashCommand } from './slash-commands/SlashCommand.js'; +import { SlashCommandNamedArgument, ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js'; +import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; +import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; +import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; +import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; +import { isFalseBoolean } from './utils.js'; +import { DOMPurify } from '../lib.js'; + +/** + * Registers slash commands for the action loader module. + */ +export function registerActionLoaderSlashCommands() { + /** + * Helper to create a closure-based handler from a SlashCommandClosure argument. + * Allows all possible slash command arg types to be passed in, but only closure is accepted. + * @param {string | SlashCommandClosure | (string | SlashCommandClosure)[]} closure - The closure argument + * @param {Object} options - Configuration options + * @param {string} [options.argName='onStop'] - Name of the argument for error messages + * @param {boolean} [options.throwInvalid=true] - Whether to throw an error for invalid input + * @returns {(() => Promise)|null} The handler function, or null if no closure + */ + function createClosureHandler(closure, { argName = 'onStop', throwInvalid = true } = {}) { + if (!(closure instanceof SlashCommandClosure)) { + if (closure && throwInvalid) { + // Throw error on purpose. This is defined as a syntax error. + throw new Error(t`Invalid argument for ${argName} provided. This is not a closure.`); + } + return null; + } + return async () => { + try { + const localClosure = closure.getCopy(); + localClosure.onProgress = () => { }; + await localClosure.execute(); + } catch (e) { + console.error('Error executing closure handler', e); + } + }; + } + + // Shared loader enum providers + const loaderEnumProviders = { + toastModeEnumProvider: () => [ + new SlashCommandEnumValue(ActionLoaderToastMode.NONE, 'No toast displayed', enumTypes.enum, enumIcons.disabled), + new SlashCommandEnumValue(ActionLoaderToastMode.STATIC, 'Static toast without stop button', enumTypes.enum, enumIcons.spinner), + new SlashCommandEnumValue(ActionLoaderToastMode.STOPPABLE, 'Toast with stop button (default)', enumTypes.enum, enumIcons.stop), + ], + loaderHandleProvider: () => getActiveLoaderHandles().map( + handle => new SlashCommandEnumValue(handle.id, `Active loader: ${handle.id}`, enumTypes.enum, enumIcons.spinner), + ).concat( + new SlashCommandEnumValue('Temporary loader handle', 'Any loader handle saved in variables or similar', 'enum', '📄', () => true, () => ''), + ), + }; + + // /loader-wrap command - wraps a closure with loader display + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'loader-wrap', + returns: 'result of the closure execution', + helpString: ` +
+ Wraps a closure execution with an action loader overlay and optional toast notification. + By default, the loader blocks UI interaction until the closure completes. + Multiple loaders can be stacked - each gets its own toast, but the overlay stays single. +
+
+ Toast modes: +
    +
  • stoppable - Shows toast with a stop button (default)
  • +
  • static - Shows toast without stop button
  • +
  • none - No toast, only loader overlay
  • +
+
+
+ Set blocking=false to show only a toast without blocking the UI. + Useful for background operations like image captioning or generation. +
+
+ The default stop behavior is calling stopGeneration(). + If the wrapped action is doing something different than generating, a custom stop closure can be provided. +
+
+ Examples: +
    +
  • /loader-wrap message="Generating summary..." {: /gen Summary of the last message | /echo Done :}
  • +
  • /loader-wrap blocking=false message="Captioning..." {: /caption :}
  • +
  • /loader-wrap toast=stoppable onStop={: /echo "Stopped by user" :} {: /delay 10000 :}
  • +
+
+ `, + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'blocking', + description: 'Whether to show blocking overlay. Set to false for non-blocking toast-only loaders.', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'true', + enumList: commonEnumProviders.boolean()(), + }), + SlashCommandNamedArgument.fromProps({ + name: 'toast', + description: 'Toast display mode: stoppable (with stop button), static (no stop button), or none', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: ActionLoaderToastMode.STOPPABLE, + enumList: loaderEnumProviders.toastModeEnumProvider(), + }), + SlashCommandNamedArgument.fromProps({ + name: 'message', + description: 'Message to display in the toast notification', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'Generating...', + }), + SlashCommandNamedArgument.fromProps({ + name: 'title', + description: 'Optional title for the toast notification', + typeList: [ARGUMENT_TYPE.STRING], + }), + SlashCommandNamedArgument.fromProps({ + name: 'slug', + description: 'Unique slug for the loader (to identify it easily via code or CSS)', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'slash-wrap', + }), + SlashCommandNamedArgument.fromProps({ + name: 'stopTooltip', + description: 'Tooltip text for the stop button (only used when toast=stoppable)', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'Stop', + }), + SlashCommandNamedArgument.fromProps({ + name: 'onStop', + description: 'Closure to execute when the stop button is clicked. If not provided, uses default stop behavior.', + typeList: [ARGUMENT_TYPE.CLOSURE], + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'Closure to execute while the loader is displayed', + typeList: [ARGUMENT_TYPE.CLOSURE], + isRequired: true, + }), + ], + callback: async (args, value) => { + if (!(value instanceof SlashCommandClosure)) { + // Throw error on purpose. This is defined as a syntax error. + throw new Error(t`Invalid argument for unnamed argument provided. This is not a closure.`); + } + + const blocking = !isFalseBoolean(String(args.blocking)); + const toastMode = Object.values(ActionLoaderToastMode).includes(String(args.toast)) + ? String(args.toast) + : ActionLoaderToastMode.STOPPABLE; + const message = String(args.message ?? t`Generating...`); + const title = args.title ? String(args.title) : ''; + const stopTooltip = String(args.stopTooltip ?? t`Stop`); + + const actionLoader = loader.show({ + slug: typeof args.slug === 'string' ? String(args.slug) : 'slash-wrap', + blocking, + toastMode, + message, + title, + stopTooltip, + onStop: createClosureHandler(args.onStop), + }); + + try { + const closureCopy = value.getCopy(); + const result = await closureCopy.execute(); + return result.pipe; + } finally { + await actionLoader.hide(); + } + }, + })); + + // /loader-show command - manually show a loader, returns handle ID + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'loader-show', + returns: 'loader handle ID (use with /loader-hide)', + helpString: ` +
+ Manually shows an action loader. Returns a handle ID that can be used with /loader-hide to hide it. + Use this for fine-grained control when you need to show/hide the loader at specific points. + Multiple loaders can be stacked - each gets its own toast, but the overlay stays single. +
+
+ Toast modes: +
    +
  • stoppable - Shows toast with a stop button (default)
  • +
  • static - Shows toast without stop button
  • +
  • none - No toast, only loader overlay
  • +
+
+
+ Set blocking=false to show only a toast without blocking the UI. + Useful for background operations like image captioning or generation. +
+
+ The default stop behavior is calling stopGeneration(). + If the wrapped action is doing something different than generating, a custom stop closure can be provided. +
+
+ Example: +
+                    
+/loader-show message="Loading..." |
+/setvar key=myLoader |
+/some-operation |
+/loader-hide handle={{getvar::myLoader}}
+                    
+                
+
+ `, + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'blocking', + description: 'Whether to show blocking overlay. Set to false for non-blocking toast-only loaders.', + typeList: [ARGUMENT_TYPE.BOOLEAN], + defaultValue: 'true', + enumList: commonEnumProviders.boolean()(), + }), + SlashCommandNamedArgument.fromProps({ + name: 'toast', + description: 'Toast display mode: stoppable (with stop button), static (no stop button), or none', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: ActionLoaderToastMode.STOPPABLE, + enumList: loaderEnumProviders.toastModeEnumProvider(), + }), + SlashCommandNamedArgument.fromProps({ + name: 'message', + description: 'Message to display in the toast notification', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'Generating...', + }), + SlashCommandNamedArgument.fromProps({ + name: 'title', + description: 'Optional title for the toast notification', + typeList: [ARGUMENT_TYPE.STRING], + }), + SlashCommandNamedArgument.fromProps({ + name: 'slug', + description: 'Unique slug for the loader (to identify it easily via code or CSS)', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'slash-show', + }), + SlashCommandNamedArgument.fromProps({ + name: 'stopTooltip', + description: 'Tooltip text for the stop button (only used when toast=stoppable)', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'Stop', + }), + SlashCommandNamedArgument.fromProps({ + name: 'onStop', + description: 'Closure to execute when the stop button is clicked', + typeList: [ARGUMENT_TYPE.CLOSURE], + }), + SlashCommandNamedArgument.fromProps({ + name: 'onHide', + description: 'Closure to execute when the loader is hidden (not stopped)', + typeList: [ARGUMENT_TYPE.CLOSURE], + }), + ], + unnamedArgumentList: [], + callback: async (args) => { + const blocking = !isFalseBoolean(String(args.blocking)); + const toastMode = Object.values(ActionLoaderToastMode).includes(String(args.toast)) + ? String(args.toast) + : ActionLoaderToastMode.STOPPABLE; + const message = String(args.message ?? t`Generating...`); + const title = args.title ? String(args.title) : ''; + const stopTooltip = String(args.stopTooltip ?? t`Stop`); + + const handle = loader.show({ + slug: typeof args.slug === 'string' ? String(args.slug) : 'slash-show', + blocking, + toastMode, + message: DOMPurify.sanitize(message), + title: DOMPurify.sanitize(title), + stopTooltip, + onStop: createClosureHandler(args.onStop), + onHide: createClosureHandler(args.onHide, { argName: 'onHide' }), + }); + + return handle.id; + }, + })); + + // /loader-hide command - manually hide a loader by handle ID + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'loader-hide', + returns: 'true if an active loader was hidden, otherwise false', + helpString: ` +
+ Hides an action loader that was shown with /loader-show. + If no handle is provided, hides all active loaders. +
+
+ Example: +
/loader-hide handle={{getvar::myLoader}}
+
+ `, + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'handle', + description: 'Loader handle ID returned by /loader-show. If not provided, hides all active loaders.', + typeList: [ARGUMENT_TYPE.STRING], + enumProvider: loaderEnumProviders.loaderHandleProvider, + }), + ], + callback: async (args) => { + const handleId = args.handle ? String(args.handle) : null; + + if (handleId) { + const handle = getLoaderHandleById(handleId); + if (handle && handle.isActive) { + await handle.hide(); + return 'true'; + } + return 'false'; + } + + // No handle provided - hide all active loaders + const result = await loader.hide(); + return result ? 'true' : 'false'; + }, + })); + + // /loader-stop command - trigger the stop action on a loader + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'loader-stop', + returns: 'true if an active loader was stopped, otherwise false', + helpString: ` +
+ Triggers the stop action on a specific action loader, as if the user clicked the stop button. + Unlike /loader-hide, this command requires a handle - you must specify which loader to stop. +
+
+ Example: +
/loader-stop handle={{getvar::myLoader}}
+
+ `, + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'handle', + description: 'Loader handle ID returned by /loader-show.', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + enumProvider: loaderEnumProviders.loaderHandleProvider, + }), + ], + callback: async (args) => { + const handleId = args.handle ? String(args.handle) : null; + + if (!handleId) { + toastr.warning(t`No handle provided. You must specify which loader to stop.`); + return 'false'; + } + + const handle = getLoaderHandleById(handleId); + if (handle && handle.isActive) { + await handle.stop(); + return 'true'; + } + + return 'false'; + }, + })); +} diff --git a/src/scripts/action-loader.js b/src/scripts/action-loader.js new file mode 100644 index 00000000..2108a9a7 --- /dev/null +++ b/src/scripts/action-loader.js @@ -0,0 +1,617 @@ +/** + * Unified action loader system - shows loader overlay with optional toast notifications. + * Designed to be flexible and reusable for various long-running operations. + * + * Features: + * - Stacking multiple loaders - overlay stays single, but toasts can stack + * - Blocking and non-blocking modes + * - Stoppable or static toasts + * - Class-based handle system for fine-grained control + * + * @module action-loader + */ + +import { t } from './i18n.js'; +import { stopGeneration } from '../script.js'; +import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js'; + +/** + * Enum representing the toast display mode for the action loader. + * @readonly + * @enum {string} + */ +export const ActionLoaderToastMode = { + /** No toast is displayed */ + NONE: 'none', + /** Toast is displayed without stop button (non-interactable) */ + STATIC: 'static', + /** Toast is displayed with stop button (default) */ + STOPPABLE: 'stoppable', +}; + +/** + * @typedef {object} ActionLoaderOptions + * @property {boolean} [blocking=true] - Whether to show the blocking overlay. Set to false for non-blocking toast-only loaders. + * @property {ActionLoaderToastMode} [toastMode='stoppable'] - Toast display mode + * @property {string} [slug=null] - Unique slug for the loader to identify it easily via code or CSS + * @property {string} [message='Generating...'] - The message to display in the toast + * @property {string} [title] - Optional title for the toast notification + * @property {string} [stopTooltip='Stop'] - Tooltip text for the stop button + * @property {HTMLElement|string|null} [overlayContent=null] - Custom content for the overlay (replaces default spinner) + * @property {(() => void)|null} [onStop=null] - Custom stop handler. If null, calls `stopGeneration()` + * @property {(() => void)|null} [onHide=null] - Custom hide handler. Called when the loader is hidden (not stopped). + */ + +/** Counter for generating unique loader IDs */ +let loaderIdCounter = 0; + +/** @type {Set} Set of all active loader handles */ +const activeHandles = new Set(); + +/** + * Generates a unique loader ID. + * @returns {string} Unique loader ID + */ +function generateLoaderId() { + return `loader_${++loaderIdCounter}`; +} + +/** + * Checks if there are any active blocking loaders. + * @returns {boolean} True if at least one blocking loader is active + */ +function hasBlockingLoaders() { + for (const handle of activeHandles) { + if (handle.isBlocking && handle.isActive) { + return true; + } + } + return false; +} + +/** + * Class representing an action loader handle. + * Manages its own toast, stop handler, and lifecycle. + */ +export class ActionLoaderHandle { + /** + * A special empty handle that is already disposed. Useful as a default value to avoid null checks. + * Does not generate any id, toast, or overlay, and all its methods are no-ops. + * @type {ActionLoaderHandle} + */ + static get EMPTY() { + return new ActionLoaderHandle({ predisposed: true }); + } + + /** @type {string} Unique identifier for this handle */ + #id; + + /** @type {string|null} Unique slug for the loader */ + #slug = null; + + /** @type {JQuery|null} The toast element for this loader */ + #toast = null; + + /** @type {(() => void)|null} Custom stop handler */ + #onStop = null; + + /** @type {(() => void)|null} Custom hide handler */ + #onHide = null; + + /** @type {boolean} Whether this loader blocks the UI with an overlay */ + #blocking = true; + + /** @type {boolean} Whether this handle has been disposed */ + #disposed = false; + + /** + * Creates a new ActionLoaderHandle. + * @param {object} options - Configuration options + * @param {boolean} [options.blocking=true] - Whether to show blocking overlay + * @param {ActionLoaderToastMode} [options.toastMode] - Toast display mode + * @param {string|null} [options.slug] - Unique slug for the loader (to identify it easily via code or CSS) + * @param {string} [options.message='Generating...'] - Message to display in the toast + * @param {string} [options.title] - Title for the toast notification + * @param {string} [options.stopTooltip='Stop'] - Tooltip for the stop button + * @param {boolean} [options.predisposed=false] - Whether this handle is already disposed (for special use) + * @param {HTMLElement|string|null} [options.overlayContent] - Custom content for the overlay (replaces default spinner) + * @param {(() => void)|null} [options.onStop] - Custom stop handler + * @param {(() => void)|null} [options.onHide] - Custom hide handler + */ + constructor({ + blocking = true, + toastMode = ActionLoaderToastMode.STOPPABLE, + slug = null, + message = t`Generating...`, + title = '', + stopTooltip = t`Stop`, + overlayContent = null, + onStop = null, + onHide = null, + predisposed = false, + } = {}) { + if (predisposed) { + this.#disposed = true; + return; + } + + this.#id = generateLoaderId(); + this.#slug = slug; + this.#blocking = blocking; + this.#onStop = onStop; + this.#onHide = onHide; + + // Warn if non-blocking loader has no toast - it won't be visible to the user + if (!blocking && toastMode === ActionLoaderToastMode.NONE && !overlayContent) { + console.warn('[ActionLoader] Non-blocking loader created without a toast. This loader will not be visible to the user.'); + } + + // Show the blocking loader overlay if this is the first blocking handle + if (blocking && !hasBlockingLoaders() && !isOverlayDisplayed()) { + showOverlay(overlayContent); + } + + // Register this handle + activeHandles.add(this); + + // Create toast if needed + if (toastMode !== ActionLoaderToastMode.NONE) { + this.#createToast(message, title, toastMode, stopTooltip); + } + } + + /** + * Creates the toast element for this loader. + * @param {string} message - Message to display + * @param {string} title - Title for the toast + * @param {ActionLoaderToastMode} toastMode - Toast mode + * @param {string} stopTooltip - Tooltip for stop button + */ + #createToast(message, title, toastMode, stopTooltip) { + const toastContent = document.createElement('div'); + toastContent.className = 'action-loader-toast'; + + if (this.#slug) { + toastContent.dataset.slug = this.#slug; + } + toastContent.dataset.loaderId = this.#id; + toastContent.dataset.blocking = this.#blocking.toString(); + + const messageSpan = document.createElement('span'); + messageSpan.className = 'action-loader-message'; + messageSpan.textContent = message; + toastContent.appendChild(messageSpan); + + // Add stop button if mode is STOPPABLE + if (toastMode === ActionLoaderToastMode.STOPPABLE) { + const stopButton = document.createElement('i'); + stopButton.className = 'fa-solid fa-stop-circle action-loader-stop interactable'; + stopButton.title = stopTooltip; + stopButton.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + this.stop(); + }); + toastContent.appendChild(stopButton); + } + + // Show toast with no timeout (sticky) + this.#toast = toastr.info($(toastContent), title, { + timeOut: 0, + extendedTimeOut: 0, + tapToDismiss: false, + escapeHtml: false, + }); + } + + /** + * Clears the toast element for this loader. + */ + #clearToast() { + if (this.#toast) { + toastr.clear(this.#toast, { force: true }); // Need to force as the toast might have focus/hover + this.#toast = null; + } + } + + /** + * Disposes this handle, removing it from active handles and hiding overlay if last. + */ + async #dispose() { + if (this.#disposed) return; + this.#disposed = true; + + this.#clearToast(); + activeHandles.delete(this); + + // Hide the overlay if this was the last blocking handle + if (this.#blocking && !hasBlockingLoaders()) { + await hideOverlay(); + } + } + + /** + * The unique identifier for this loader handle. + * @returns {string} + */ + get id() { + return this.#id; + } + + /** + * The unique slug for this loader handle, used to identify it easily via code or CSS. + * @returns {string|null} + */ + get slug() { + return this.#slug; + } + + /** + * Whether this handle is still active (not disposed). + * @returns {boolean} + */ + get isActive() { + return !this.#disposed; + } + + /** + * Whether this loader blocks the UI with an overlay. + * @returns {boolean} + */ + get isBlocking() { + return this.#blocking; + } + + /** + * Triggers the stop action on this loader. + * Calls the custom onStop handler if provided, otherwise calls stopGeneration(). + * Then hides this loader. + */ + async stop() { + if (this.#disposed) return; + + // Call custom stop handler or default + if (this.#onStop) { + try { + await this.#onStop(); + } catch (e) { + console.error('Error executing onStop handler', e); + } + } else { + stopGeneration(); + } + + // Dispose without calling onHide (stop is different from hide) + await this.#dispose(); + } + + /** + * Hides this loader and clears its toast. + * Calls the custom onHide handler if provided. + */ + async hide() { + if (this.#disposed) return; + + // Call custom hide handler if provided + if (this.#onHide) { + try { + await this.#onHide(); + } catch (e) { + console.error('Error executing onHide handler', e); + } + } + + await this.#dispose(); + } +} + +/** + * Action loader utility API. + * Provides a convenient interface for showing and managing loading indicators. + * + * Read the functions documentation for more details. + * + * @example + * // Basic usage + * const handle = loader.show({ message: 'Loading...' }); + * await someOperation(); + * handle.hide(); + * + * @example + * // Non-blocking background task + * const handle = loader.show({ blocking: false, message: 'Processing...' }); + * + * @example + * // Hide all active loaders + * loader.hide(); + */ +export const loader = { + /** + * Shows an action loader with optional toast notification. + * Returns a handle to control the loader. + * @type {typeof showActionLoader} + */ + show: showActionLoader, + + /** + * Hides a specific loader by handle, or all loaders if no handle provided. + * @type {typeof hideActionLoader} + */ + hide: hideActionLoader, + + /** + * Gets all currently active loader handles. + * @type {typeof getActiveLoaderHandles} + */ + active: getActiveLoaderHandles, + + /** + * Gets a loader handle by its ID. + * @type {typeof getLoaderHandleById} + */ + get: getLoaderHandleById, + + /** + * Checks if any blocking loader overlay is currently displayed. + * @returns {boolean} True if a blocking overlay is shown + */ + isBlocking: isOverlayDisplayed, + + /** + * Toast display mode constants. + * @type {typeof ActionLoaderToastMode} + */ + ToastMode: ActionLoaderToastMode, + + /** + * The ActionLoaderHandle class. + * @type {typeof ActionLoaderHandle} + */ + Handle: ActionLoaderHandle, + + /** + * Creates a fresh default loader overlay element. + * @type {typeof createDefaultLoaderOverlay} + */ + createOverlay: createDefaultLoaderOverlay, +}; + +/** + * Shows an action loader with an optional stoppable toast notification. + * Multiple loaders can be stacked - the overlay stays single, but each gets its own toast. + * When the last loader is hidden, the overlay is removed. + * + * With default arguments, will function as a generation loader / wrapper. + * + * @param {ActionLoaderOptions} [options={}] - Configuration options + * @returns {ActionLoaderHandle} Handle to control the loader + * + * @example + * // Basic usage + * const loader = showActionLoader({ message: 'Generating title...' }); + * try { + * const result = await generateRaw({ prompt }); + * // process result + * } finally { + * await loader.hide(); + * } + * + * @example + * // With custom stop and hide handlers + * const loader = showActionLoader({ + * message: 'Downloading...', + * stopTooltip: 'Cancel download', + * onStop: () => myCustomCancelFunction(), + * onHide: () => console.log('Loader hidden'), + * }); + * + * @example + * // Stacking multiple loaders + * const loader1 = showActionLoader({ message: 'Task 1...' }); + * const loader2 = showActionLoader({ message: 'Task 2...' }); + * await loader1.hide(); // Overlay stays, loader2 still active + * await loader2.hide(); // Now overlay hides + * + * @example + * // Non-blocking loader (toast only, no overlay) + * const loader = showActionLoader({ + * message: 'Captioning image...', + * blocking: false, + * onStop: () => abortCaptioning(), + * }); + */ +export function showActionLoader(options = {}) { + return new ActionLoaderHandle(options); +} + +/** + * Hides a specific action loader by handle, or all active loaders if no handle provided. + * @param {ActionLoaderHandle|null} [handle=null] - Specific handle to hide, or undefined to hide all + * @returns {Promise} Whether any loader was hidden + */ +export async function hideActionLoader(handle = null) { + if (handle instanceof ActionLoaderHandle) { + if (handle.isActive) { + await handle.hide(); + return true; + } + return false; + } + + // No handle provided - hide all active loaders + const handles = getActiveLoaderHandles(); + for (const h of handles) { + await h.hide(); + } + return handles.length > 0; +} + +/** + * Gets all currently active loader handles. + * @returns {ActionLoaderHandle[]} Array of active handles + */ +export function getActiveLoaderHandles() { + return Array.from(activeHandles); +} + +/** + * Gets a loader handle by its ID. + * @param {string} id - The handle ID + * @returns {ActionLoaderHandle|undefined} The handle, or undefined if not found + */ +export function getLoaderHandleById(id) { + for (const handle of activeHandles) { + if (handle.id === id) { + return handle; + } + } + return undefined; +} + +// ============================================================================ +// Internal overlay management +// ============================================================================ + +/** @type {Popup|null} The current loader overlay popup */ +let loaderPopup = null; + +/** Whether the initial HTML preloader has been removed */ +let preloaderYoinked = false; + +/** + * Creates the default loader overlay element. + * Always returns a fresh element instance. + * + * @returns {HTMLDivElement} A new loader overlay element + */ +export function createDefaultLoaderOverlay() { + const loaderElement = document.createElement('div'); + loaderElement.id = 'loader'; + + const spinnerElement = document.createElement('div'); + spinnerElement.id = 'load-spinner'; + spinnerElement.className = 'fa-solid fa-gear fa-spin fa-3x'; + + loaderElement.appendChild(spinnerElement); + + return loaderElement; +} + +/** + * Normalizes custom overlay content into a value supported by Popup. + * @param {string|HTMLElement|null} customContent - Custom overlay content + * @returns {string|HTMLElement} Content for Popup + */ +function getOverlayContent(customContent) { + if (typeof customContent === 'string') { + return customContent; + } + + if (customContent instanceof HTMLElement) { + return customContent; + } + + return createDefaultLoaderOverlay(); +} + +/** + * Checks if the loader overlay is currently displayed. + * @returns {boolean} True if overlay is shown + */ +function isOverlayDisplayed() { + return !!loaderPopup; +} + +/** + * Shows the blocking loader overlay. + * Internal function - use showActionLoader() instead. + * @param {HTMLElement|string|null} [customContent] - Custom content for the overlay + */ +function showOverlay(customContent = null) { + // Two loaders don't make sense. Don't await, we can overlay the old loader while it closes + if (loaderPopup) loaderPopup.complete(POPUP_RESULT.CANCELLED); + + const content = getOverlayContent(customContent); + + loaderPopup = new Popup(content, POPUP_TYPE.DISPLAY, null, { + allowEscapeClose: false, + transparent: true, + animation: 'none', + wide: true, + large: true, + }); + + // No close button, loaders are not closable + loaderPopup.closeButton.style.display = 'none'; + + loaderPopup.show(); +} + +/** + * Hides the blocking loader overlay with animation. + * Internal function - use hideActionLoader() instead. + * @returns {Promise} + */ +async function hideOverlay() { + if (!loaderPopup) { + return Promise.resolve(); + } + + return new Promise((resolve) => { + const loaderElement = $('#loader'); + const spinner = $('#load-spinner'); + + if (!loaderElement.length) { + console.warn('Loader element not found, skipping animation'); + cleanup(); + return; + } + + // Check if transitions are enabled on spinner (which has the transition property) + const transitionDuration = spinner.length && spinner[0] ? getComputedStyle(spinner[0]).transitionDuration : '0s'; + const hasTransitions = parseFloat(transitionDuration) > 0; + + if (hasTransitions) { + Promise.race([ + new Promise((r) => setTimeout(r, 500)), // Fallback timeout + new Promise((r) => loaderElement.one('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', r)), + ]).finally(cleanup); + } else { + cleanup(); + } + + function cleanup() { + loaderElement.remove(); + // Yoink preloader entirely; it only exists to cover up unstyled content while loading JS + // If it's present, we remove it once and then it's gone. + yoinkPreloader(); + + loaderPopup.complete(POPUP_RESULT.AFFIRMATIVE) + .catch((err) => console.error('Error completing loaderPopup:', err)) + .finally(() => { + loaderPopup = null; + resolve(); + }); + } + + // Apply the blur styles to the entire loader element + loaderElement.css({ + 'filter': 'blur(15px)', + 'opacity': '0', + }); + }); +} + +/** + * Removes the initial HTML preloader element. + * Called once after the first loader hide. + */ +function yoinkPreloader() { + if (preloaderYoinked) return; + document.getElementById('preloader')?.remove(); + preloaderYoinked = true; +} + +// ============================================================================ +// End internal overlay management +// ============================================================================ diff --git a/src/scripts/bookmarks.js b/src/scripts/bookmarks.js index e238376c..550bfd05 100644 --- a/src/scripts/bookmarks.js +++ b/src/scripts/bookmarks.js @@ -2,6 +2,7 @@ import { characters, saveChat, system_message_types, + syncSwipeToMes, this_chid, openCharacterChat, chat_metadata, @@ -25,7 +26,7 @@ import { saveGroupBookmarkChat, selected_group, } from './group-chats.js'; -import { hideLoader, showLoader } from './loader.js'; +import { loader } from './action-loader.js'; import { getLastMessageId } from './macros.js'; import { Popup } from './popup.js'; import { SlashCommand } from './slash-commands/SlashCommand.js'; @@ -34,6 +35,7 @@ import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsPro import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; import { createTagMapFromList } from './tags.js'; import { renderTemplateAsync } from './templates.js'; +import { compressRequest } from './request-compression.js'; import { t } from './i18n.js'; import { @@ -111,12 +113,10 @@ function getMainChatName() { if (chat_metadata) { if (chat_metadata.main_chat) { return chat_metadata.main_chat; - } - // groups didn't support bookmarks before chat metadata was introduced - else if (selected_group) { + } else if (selected_group) { + // groups didn't support bookmarks before chat metadata was introduced return null; - } - else if (characters[this_chid].chat && characters[this_chid].chat.includes(bookmarkNameToken)) { + } else if (characters[this_chid].chat && characters[this_chid].chat.includes(bookmarkNameToken)) { const tokenIndex = characters[this_chid].chat.lastIndexOf(bookmarkNameToken); chat_metadata.main_chat = characters[this_chid].chat.substring(0, tokenIndex).trim(); return chat_metadata.main_chat; @@ -146,8 +146,7 @@ export function showBookmarksButtons() { $('#option_back_to_main').hide(); $('#option_new_bookmark').show(); } - } - catch { + } catch { $('#option_back_to_main').hide(); $('#option_new_bookmark').hide(); $('#option_convert_to_group').hide(); @@ -163,8 +162,28 @@ async function saveBookmarkMenu() { return await createNewBookmark(chat.length - 1); } +/** + * Builds the branch chat snapshot, optionally selecting a specific swipe for the target message. + * @param {number} mesId + * @param {{swipeId?: number|null}} [options={}] + * @returns {ChatMessage[]|null} + */ +function getBranchChatSnapshot(mesId, { swipeId = null } = {}) { + const snapshot = structuredClone(chat.slice(0, Number(mesId) + 1)); + + if (swipeId === null) { + return snapshot; + } + + if (!syncSwipeToMes(null, swipeId, snapshot[mesId])) { + return null; + } + + return snapshot; +} + // Export is used by Timelines extension. Do not remove. -export async function createBranch(mesId) { +export async function createBranch(mesId, { swipeId = null } = {}) { if (!chat.length) { toastr.warning('The chat is empty.', 'Branch creation failed'); return; @@ -178,6 +197,12 @@ export async function createBranch(mesId) { const lastMes = chat[mesId]; const mainChatName = (getCurrentChatDetails()).sessionName; const newMetadata = { main_chat: mainChatName }; + const selectedSwipeId = swipeId === null ? null : Number(swipeId); + + if (selectedSwipeId !== null && (!Number.isInteger(selectedSwipeId) || selectedSwipeId < 0 || selectedSwipeId >= (lastMes?.swipes?.length ?? 0))) { + toastr.warning('Invalid swipe ID.', 'Branch creation failed'); + return; + } function buildBranchName(name, i) { // Strip off existing suffixes, then build new name @@ -194,10 +219,16 @@ export async function createBranch(mesId) { return; } + const branchChatSnapshot = getBranchChatSnapshot(mesId, { swipeId: selectedSwipeId }); + if (!branchChatSnapshot) { + toastr.warning('Could not prepare the selected swipe for branching.', 'Branch creation failed'); + return; + } + if (selected_group) { - await saveGroupBookmarkChat(selected_group, name, newMetadata, mesId); + await saveGroupBookmarkChat(selected_group, name, newMetadata, mesId, branchChatSnapshot); } else { - await saveChat({ chatName: name, withMetadata: newMetadata, mesId }); + await saveChat({ chatName: name, withMetadata: newMetadata, mesId, chatData: branchChatSnapshot }); } // append to branches list if it exists // otherwise create it @@ -389,11 +420,12 @@ export async function convertSoloToGroupChat() { } // Save group chat - const createChatResponse = await fetch('/api/chats/group/save', { + const createChatRequest = await compressRequest({ method: 'POST', headers: getRequestHeaders(), body: JSON.stringify({ id: chatName, chat: [chatHeader, ...groupChat] }), }); + const createChatResponse = await fetch('/api/chats/group/save', createChatRequest); if (!createChatResponse.ok) { console.error('Group chat creation unsuccessful'); @@ -411,15 +443,20 @@ export async function convertSoloToGroupChat() { /** * Creates a new branch from the message with the given ID * @param {number} mesId Message ID + * @param {{swipeId?: number|null}} [options={}] Branch options * @returns {Promise} Branch file name */ -export async function branchChat(mesId) { +export async function branchChat(mesId, { swipeId = null } = {}) { if (this_chid === undefined && !selected_group) { toastr.info('No character selected.', 'Create Branch'); return null; } - const fileName = await createBranch(mesId); + const fileName = await createBranch(mesId, { swipeId }); + if (!fileName) { + return null; + } + await saveItemizedPrompts(fileName); if (selected_group) { @@ -662,15 +699,21 @@ export function initBookmarks() { return; } + const loaderHandle = loader.show({ + slug: 'chat-load', + title: t`Chat History`, + message: t`Loading chat…`, + toastMode: loader.ToastMode.STATIC, + }); + try { - showLoader(); if (selected_group) { await openGroupChat(selected_group, fileName); } else { await openCharacterChat(fileName); } } finally { - await hideLoader(); + await loaderHandle.hide(); } $('#shadow_select_chat_popup').css('display', 'none'); diff --git a/src/scripts/bulk-edit.js b/src/scripts/bulk-edit.js index 404e07a0..bb09551c 100644 --- a/src/scripts/bulk-edit.js +++ b/src/scripts/bulk-edit.js @@ -55,7 +55,7 @@ function onSelectAllButtonClick() { if (!atLeastOneSelected) { // If none was selected, trigger click on all to deselect all of them - for(const character of characters) { + for (const character of characters) { const checked = $(character).find('.bulk_select_checkbox:checked') ?? false; if (checked && character instanceof HTMLElement) { characterGroupOverlay.toggleSingleCharacter(character); diff --git a/src/scripts/cfg-scale.js b/src/scripts/cfg-scale.js index 801e78af..56b5995e 100644 --- a/src/scripts/cfg-scale.js +++ b/src/scripts/cfg-scale.js @@ -150,7 +150,6 @@ function onCfgMenuItemClick() { setTimeout(function () { $('#cfgConfig').hide(); }, animation_duration); - } //duplicate options menu close handler from script.js //because this listener takes priority diff --git a/src/scripts/chat-backups.js b/src/scripts/chat-backups.js index 437b8787..966bd78f 100644 --- a/src/scripts/chat-backups.js +++ b/src/scripts/chat-backups.js @@ -199,7 +199,7 @@ class BackupsBrowser { const deleteButton = document.createElement('div'); deleteButton.classList.add('right_menu_button', 'fa-solid', 'fa-trash'); deleteButton.title = t`Delete backup`; - deleteButton.addEventListener('click',async () => { + deleteButton.addEventListener('click', async () => { const isDeleted = await this.deleteBackup(backup.file_name); if (isDeleted) { listItem.remove(); diff --git a/src/scripts/constants.js b/src/scripts/constants.js index 7d03158c..83777915 100644 --- a/src/scripts/constants.js +++ b/src/scripts/constants.js @@ -175,6 +175,8 @@ export const SWIPE_SOURCE = { KEYBOARD: 'keyboard', BACK: 'back', AUTO_SWIPE: 'auto_swipe', + SLASH_COMMAND: 'slash_command', + SWIPE_PICKER: 'swipe_picker', }; /** diff --git a/src/scripts/extensions.js b/src/scripts/extensions.js index 6e9ff8bb..d562749a 100644 --- a/src/scripts/extensions.js +++ b/src/scripts/extensions.js @@ -1,10 +1,9 @@ -import { DOMPurify, Popper, getHljs } from '../lib.js'; +import { Popper, getHljs } from '../lib.js'; import { eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration, CLIENT_VERSION } from '../script.js'; -import { showLoader } from './loader.js'; import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; import { renderTemplate, renderTemplateAsync } from './templates.js'; -import { delay, equalsIgnoreCaseAndAccents, isSubsetOf, sanitizeSelector, setValueByPath, versionCompare } from './utils.js'; +import { delay, deleteValueByPath, equalsIgnoreCaseAndAccents, escapeHtml, isSubsetOf, sanitizeSelector, setValueByPath, versionCompare } from './utils.js'; import { getContext } from './st-context.js'; import { isAdmin } from './user.js'; import { addLocaleData, getCurrentLocale, t, translate } from './i18n.js'; @@ -82,6 +81,19 @@ let offlineExtensionsPreparationPromise = null; */ const defaultUrl = 'http://localhost:5100'; +/** + * Checks if the extension is officially supported by its URL pattern. + * @param {string} url URL to check + * @returns {boolean} True if the URL matches the pattern, false otherwise (or not a valid URL) + */ +export const isOfficialExtension = (url) => { + try { + return /^https:\/\/github\.com\/SillyTavern\/(.+)$/i.test(new URL(url).href); + } catch (e) { + return false; + } +}; + let requiresReload = false; let stateChanged = false; let saveMetadataTimeout = null; @@ -320,6 +332,18 @@ export async function doExtrasFetch(endpoint, args = {}) { return await fetch(endpoint, args); } +/** + * Generates a CSS selector for an extension based on its name, allowing omission of a common prefix. + * @param {string} name Name of the extension, with or without the "third-party" prefix + * @param {object} [options] Optional parameters + * @param {string} [options.prefix] Optional prefix to ignore when generating the selector (e.g. "third-party") + * @returns {string} CSS selector for the extension, with the prefix removed if it was present and specified in options + */ +function getNameSelector(name, { prefix = 'third-party' } = {}) { + const nameWithoutPrefix = prefix && name.startsWith(prefix) ? name.slice(prefix.length) : name; + return CSS.escape(nameWithoutPrefix); +} + /** * Discovers extensions from the API. * @returns {Promise<{name: string, type: string}[]>} @@ -331,12 +355,10 @@ async function discoverExtensions() { if (response.ok) { const extensions = await response.json(); return extensions; - } - else { + } else { return []; } - } - catch (err) { + } catch (err) { console.error(err); return []; } @@ -451,7 +473,7 @@ function onToggleAllExtensions(extensionsToToggle, toggleContainer) { } toggleContainer - .find(`.extension_block[data-name="${name.replace('third-party', '')}"] .extension_toggle input`) + .find(`.extension_block[data-name="${getNameSelector(name)}"] .extension_toggle input`) .prop('checked', enable) .toggleClass('toggle_enable', !enable) .toggleClass('toggle_disable', enable) @@ -462,12 +484,99 @@ function onToggleAllExtensions(extensionsToToggle, toggleContainer) { return extensionsToToggle; } +/** + * Checks whether an extension has a specific hook defined in its manifest. + * @param {string} name Extension name (with or without 'third-party' prefix) + * @param {'install' | 'update' | 'delete' | 'clean' | 'enable' | 'disable' | 'activate'} hookName The hook to check + * @returns {boolean} + */ +function hasExtensionHook(name, hookName) { + const fullName = name.startsWith('third-party') ? name : `third-party${name}`; + const manifest = manifests[fullName]; + if (!manifest || !manifest.hooks || typeof manifest.hooks !== 'object') { + return false; + } + const hookFunctionName = manifest.hooks[hookName]; + return typeof hookFunctionName === 'string' && hookFunctionName.length > 0; +} + +/** + * Calls a manifest hook for an extension. + * Hooks are optional function names exported from the extension's JS entry point module. + * The hook function can optionally return a Promise that will be awaited. + * @param {string} name Extension name + * @param {'install' | 'update' | 'delete' | 'clean' | 'enable' | 'disable' | 'activate'} hookName The hook to call + * @returns {Promise} + */ +async function callExtensionHook(name, hookName) { + const manifest = manifests[name]; + + if (!manifest) { + console.debug(`callExtensionHook: Extension "${name}" has no manifest, skipping hook "${hookName}"`); + return; + } + + if (!manifest.hooks || typeof manifest.hooks !== 'object') { + return; + } + + if (!Object.hasOwn(manifest.hooks, hookName)) { + return; + } + + const hookFunctionName = manifest.hooks[hookName]; + + if (typeof hookFunctionName !== 'string' || !hookFunctionName) { + console.warn(`callExtensionHook: Extension "${name}" hook "${hookName}" is not a valid string`); + return; + } + + if (!manifest.js) { + console.warn(`callExtensionHook: Extension "${name}" has hook "${hookName}" but no JS entry point defined in manifest`); + return; + } + + const url = getExtensionResourceUrl(name, manifest.js); + console.debug(`callExtensionHook: Calling hook "${hookName}" (function "${hookFunctionName}") for extension "${name}"`); + + try { + const module = await import(url); + + if (typeof module[hookFunctionName] !== 'function') { + console.warn(`callExtensionHook: Extension "${name}" hook "${hookName}" references "${hookFunctionName}" which is not an exported function`); + return; + } + + const hookCallResult = module[hookFunctionName](); + + const HOOK_TIMEOUT = 5000; + const HOOK_RESULT = { + OK: 'ok', + TIMEOUT: 'timeout', + }; + + const result = await Promise.race([ + (hookCallResult instanceof Promise ? hookCallResult : Promise.resolve(hookCallResult)).then(() => HOOK_RESULT.OK), + delay(HOOK_TIMEOUT).then(() => HOOK_RESULT.TIMEOUT), + ]); + + if (result === HOOK_RESULT.TIMEOUT) { + console.warn(`callExtensionHook: Hook "${hookName}" for extension "${name}" timed out after ${HOOK_TIMEOUT}ms`); + } else { + console.debug(`callExtensionHook: Hook "${hookName}" completed for extension "${name}"`); + } + } catch (error) { + console.error(`callExtensionHook: Error calling hook "${hookName}" for extension "${name}":`, error); + } +} + /** * Enables an extension by name. * @param {string} name Extension name * @param {boolean} [reload=true] If true, reload the page after enabling the extension */ export async function enableExtension(name, reload = true) { + await callExtensionHook(name, 'enable'); extension_settings.disabledExtensions = extension_settings.disabledExtensions.filter(x => x !== name); stateChanged = true; await saveSettings(); @@ -484,6 +593,7 @@ export async function enableExtension(name, reload = true) { * @param {boolean} [reload=true] If true, reload the page after disabling the extension */ export async function disableExtension(name, reload = true) { + await callExtensionHook(name, 'disable'); extension_settings.disabledExtensions.push(name); stateChanged = true; await saveSettings(); @@ -509,6 +619,21 @@ export function findExtension(name) { return { name: internalExtensionName, enabled: isEnabled }; } +/** + * Returns a deep clone of the manifest for the given extension name. + * Accepts either the short name (e.g. `SillyTavern-MyExtension`) or the full internal key + * (e.g. `third-party/SillyTavern-MyExtension`). Returns null if the extension is not found. + * @param {string} name - Extension name or internal key + * @returns {object|null} Cloned manifest object, or null if not found + */ +export function getExtensionManifest(name) { + const found = extensionNames.find(extName => + equalsIgnoreCaseAndAccents(extName, name) || equalsIgnoreCaseAndAccents(extName, `third-party/${name}`), + ); + const manifest = found ? manifests[found] : null; + return manifest ? structuredClone(manifest) : null; +} + /** * Loads manifest.json files for extensions. * @param {string[]} names Array of extension names @@ -658,6 +783,7 @@ async function activateExtensions({ parallelism = 1, includeExtension = () => tr await addExtensionLocale(name, manifest); await Promise.all([addExtensionScript(name, manifest), addExtensionStyle(name, manifest)]); activeExtensions.add(name); + await callExtensionHook(name, 'activate'); } catch (err) { console.log('Could not activate extension', name, err); extensionLoadErrors.add(t`Extension "${displayName}" failed to load: ${err}`); @@ -785,6 +911,7 @@ async function ensureExtensionsUiReady() { $(document).on('click', '.extensions_info .extension_block .toggle_enable', onEnableExtensionClick); $(document).on('click', '.extensions_info .extension_block .btn_update', onUpdateClick); $(document).on('click', '.extensions_info .extension_block .btn_delete', onDeleteClick); + $(document).on('click', '.extensions_info .extension_block .btn_clean', onCleanClick); $(document).on('click', '.extensions_info .extension_block .btn_move', onMoveClick); $(document).on('click', '.extensions_info .extension_block .btn_branch', onBranchClick); $('#third_party_extension_button').on('click', () => openThirdPartyExtensionMenu()); @@ -826,8 +953,7 @@ async function connectToApi(baseUrl, { parallelism = 1, includeExtension = () => } updateStatus(getExtensionsResult.ok); - } - catch { + } catch { updateStatus(false); } } @@ -878,7 +1004,7 @@ function addExtensionLocale(name, manifest) { } /** - * Generates HTML string for displaying an extension in the UI. + * Generates an element for displaying an extension in the UI. * * @param {string} name - The name of the extension. * @param {object} manifest - The manifest of the extension. @@ -886,95 +1012,180 @@ function addExtensionLocale(name, manifest) { * @param {boolean} isDisabled - Whether the extension is disabled or not. * @param {boolean} isExternal - Whether the extension is external or not. * @param {string} checkboxClass - The class for the checkbox HTML element. - * @return {string} - The HTML string that represents the extension. + * @return {HTMLElement} - The element that represents the extension. */ -function generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal, checkboxClass) { +function generateExtensionElement(name, manifest, isActive, isDisabled, isExternal, checkboxClass) { function getExtensionIcon() { const type = getExtensionType(name); + const icon = document.createElement('i'); + icon.classList.add('fa-sm', 'fa-fw', 'fa-solid'); switch (type) { case 'global': - return ''; + icon.classList.add('fa-server'); + icon.title = t`This is a global extension, available for all users.`; + break; case 'local': - return ''; + icon.classList.add('fa-user'); + icon.title = t`This is a local extension, available only for you.`; + break; case 'system': - return ''; + icon.classList.add('fa-cog'); + icon.title = t`This is a built-in extension. It cannot be deleted and updates with the app.`; + break; default: - return ''; + icon.classList.add('fa-question'); + icon.title = t`Unknown extension type.`; + break; } + return icon; } const isUserAdmin = isAdmin(); - const extensionIcon = getExtensionIcon(); const displayName = manifest.display_name; const displayVersion = manifest.version || ''; const externalId = name.replace('third-party', ''); - let originHtml = ''; - if (isExternal) { - originHtml = ''; + + // Root block + const block = document.createElement('div'); + block.classList.add('extension_block'); + block.dataset.name = externalId; + + // Toggle + const toggleDiv = document.createElement('div'); + toggleDiv.classList.add('extension_toggle'); + const toggle = document.createElement('input'); + toggle.type = 'checkbox'; + toggle.dataset.name = name; + if (isActive || isDisabled) { + toggle.title = t`Click to toggle`; + toggle.classList.add(isActive ? 'toggle_disable' : 'toggle_enable'); + if (checkboxClass) toggle.classList.add(checkboxClass); + toggle.checked = isActive; + } else { + toggle.title = t`Cannot enable extension`; + toggle.classList.add('extension_missing'); + if (checkboxClass) toggle.classList.add(checkboxClass); + toggle.disabled = true; } + toggleDiv.appendChild(toggle); + block.appendChild(toggleDiv); - let toggleElement = isActive || isDisabled ? - '` : - ``; + // Icon + const iconDiv = document.createElement('div'); + iconDiv.classList.add('extension_icon'); + iconDiv.appendChild(getExtensionIcon()); + block.appendChild(iconDiv); - let deleteButton = isExternal ? `` : ''; - let updateButton = isExternal ? `` : ''; - let moveButton = isExternal && isUserAdmin ? `` : ''; - let branchButton = isExternal && isUserAdmin ? `` : ''; - let modulesInfo = ''; + // Text block + const textBlock = document.createElement('div'); + textBlock.classList.add('flexGrow', 'extension_text_block'); + + const statusSpan = document.createElement('span'); + statusSpan.className = isActive ? 'extension_enabled' : isDisabled ? 'extension_disabled' : 'extension_missing'; + + const nameSpan = document.createElement('span'); + nameSpan.classList.add('extension_name'); + nameSpan.textContent = displayName; + + const authorSpan = document.createElement('span'); + authorSpan.classList.add('extension_author'); + + const versionSpan = document.createElement('span'); + versionSpan.classList.add('extension_version'); + versionSpan.textContent = displayVersion; + + statusSpan.append(nameSpan, authorSpan, versionSpan); if (isActive && Array.isArray(manifest.optional)) { const optional = new Set(manifest.optional); modules.forEach(x => optional.delete(x)); if (optional.size > 0) { - const optionalString = DOMPurify.sanitize([...optional].join(', ')); - modulesInfo = '
' + t`Optional modules:` + ` ${optionalString}
`; + const modulesDiv = document.createElement('div'); + modulesDiv.classList.add('extension_modules'); + const optionalSpan = document.createElement('span'); + optionalSpan.classList.add('optional'); + optionalSpan.textContent = [...optional].join(', '); + modulesDiv.append(t`Optional modules:`, ' ', optionalSpan); + statusSpan.appendChild(modulesDiv); } - } else if (!isDisabled) { // Neither active nor disabled + } else if (!isDisabled) { + // Neither active nor disabled const requirements = new Set(manifest.requires); modules.forEach(x => requirements.delete(x)); if (requirements.size > 0) { - const requirementsString = DOMPurify.sanitize([...requirements].join(', ')); - modulesInfo = `
Missing modules: ${requirementsString}
`; + const modulesDiv = document.createElement('div'); + modulesDiv.classList.add('extension_modules'); + const failureSpan = document.createElement('span'); + failureSpan.classList.add('failure'); + failureSpan.textContent = [...requirements].join(', '); + modulesDiv.append(t`Missing modules:`, ' ', failureSpan); + statusSpan.appendChild(modulesDiv); } } // if external, wrap the name in a link to the repo + if (isExternal) { + const originLink = document.createElement('a'); + originLink.appendChild(statusSpan); + textBlock.appendChild(originLink); + } else { + textBlock.appendChild(statusSpan); + } - let extensionHtml = ` -
`; + // Actions + const actionsDiv = document.createElement('div'); + actionsDiv.classList.add('extension_actions', 'flex-container', 'alignItemsCenter'); - return extensionHtml; + /** + * Helper function to create an action button for an extension. + * @param {string} cls Class name + * @param {string} dataName Name of the extension + * @param {string} title Title of the button + * @param {string} iconClasses Classes for the icon + * @returns {HTMLButtonElement} The created button element + */ + function makeActionButton(cls, dataName, title, iconClasses) { + const btn = document.createElement('button'); + btn.classList.add(cls, 'menu_button'); + btn.dataset.name = dataName; + btn.title = title; + const icon = document.createElement('i'); + icon.classList.add(...iconClasses.split(' ')); + btn.appendChild(icon); + return btn; + } + + if (isExternal) { + const updateBtn = makeActionButton('btn_update', externalId, t`Update available`, 'fa-solid fa-download fa-fw'); + updateBtn.classList.add('displayNone'); + actionsDiv.appendChild(updateBtn); + } + + if (isExternal && hasExtensionHook(externalId, 'clean')) { + actionsDiv.appendChild(makeActionButton('btn_clean', externalId, t`Clean extension data`, 'fa-fw fa-solid fa-broom')); + } + + if (isExternal && isUserAdmin) { + actionsDiv.appendChild(makeActionButton('btn_branch', externalId, t`Switch branch`, 'fa-solid fa-code-branch fa-fw')); + actionsDiv.appendChild(makeActionButton('btn_move', externalId, t`Move`, 'fa-solid fa-folder-tree fa-fw')); + } + + if (isExternal) { + actionsDiv.appendChild(makeActionButton('btn_delete', externalId, t`Delete`, 'fa-fw fa-solid fa-trash-can')); + } + + block.appendChild(actionsDiv); + + return block; } /** - * Gets extension data and generates the corresponding HTML for displaying the extension. + * Gets extension data and generates the corresponding element for displaying the extension. * * @param {Array} extension - An array where the first element is the extension name and the second element is the extension manifest. - * @return {object} - An object with 'isExternal' indicating whether the extension is external, and 'extensionHtml' for the extension's HTML string. + * @return {{isExternal: boolean, extensionElement: HTMLElement}} - An object with 'isExternal' indicating whether the extension is external, and 'extensionElement' for the extension's HTML element. */ function getExtensionData(extension) { const name = extension[0]; @@ -984,33 +1195,43 @@ function getExtensionData(extension) { const isExternal = name.startsWith('third-party'); const checkboxClass = isDisabled ? 'checkbox_disabled' : ''; + const extensionElement = generateExtensionElement(name, manifest, isActive, isDisabled, isExternal, checkboxClass); - const extensionHtml = generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal, checkboxClass); - - return { isExternal, extensionHtml }; + return { isExternal, extensionElement }; } /** * Gets the module information to be displayed. * - * @return {string} - The HTML string for the module information. + * @return {HTMLElement} - The element containing the module information. */ function getModuleInformation() { - let moduleInfo = modules.length ? `

${DOMPurify.sanitize(modules.join(', '))}

` : '

' + t`Not connected to the API!` + '

'; - return ` -

` + t`Modules provided by your Extras API:` + `

- ${moduleInfo} - `; + const container = document.createElement('div'); + + const heading = document.createElement('h3'); + heading.textContent = t`Modules provided by your Extras API:`; + container.appendChild(heading); + + const moduleInfo = document.createElement('p'); + if (modules.length) { + moduleInfo.textContent = modules.join(', '); + } else { + moduleInfo.classList.add('failure'); + moduleInfo.textContent = t`Not connected to the API!`; + } + container.appendChild(moduleInfo); + + return container; } /** - * Generates HTML for the extension load errors. - * @returns {string} HTML string containing the errors that occurred while loading extensions. + * Generates HTMLElement for the extension load errors. + * @returns {HTMLElement} - The element containing the extension load errors. */ -function getExtensionLoadErrorsHtml() { +function getExtensionLoadErrors() { if (extensionLoadErrors.size === 0) { - return ''; + return document.createElement('div'); } const container = document.createElement('div'); @@ -1022,7 +1243,7 @@ function getExtensionLoadErrorsHtml() { container.appendChild(errorElement); } - return container.outerHTML; + return container; } /** @@ -1039,22 +1260,35 @@ async function showExtensionsDetails() { initialScrollTop = oldPopup.content.scrollTop; await oldPopup.completeCancelled(); } - const htmlErrors = getExtensionLoadErrorsHtml(); - const htmlDefault = $('

' + t`Built-in Extensions:` + '

'); + const errors = getExtensionLoadErrors(); - const htmlExternal = $(`
-
-

${t`Installed Extensions:`}

-
-
-
`); + const defaultContainer = document.createElement('div'); + defaultContainer.classList.add('marginBot10'); + const defaultHeading = document.createElement('h3'); + defaultHeading.textContent = t`Built-in Extensions:`; + defaultContainer.appendChild(defaultHeading); - const htmlLoading = $(`
- - ` + t`Loading third-party extensions... Please wait...` + ` -
`); + const externalContainer = document.createElement('div'); + externalContainer.classList.add('marginBot10'); + const externalHeader = document.createElement('div'); + externalHeader.classList.add('flex-container', 'alignitemscenter', 'spaceBetween', 'flexnowrap', 'marginBot10'); + const externalHeading = document.createElement('h3'); + externalHeading.classList.add('margin0'); + externalHeading.textContent = t`Installed Extensions:`; + const thirdPartyToolbar = document.createElement('div'); + thirdPartyToolbar.classList.add('flex-container', 'third_party_toolbar'); + externalHeader.append(externalHeading, thirdPartyToolbar); + externalContainer.appendChild(externalHeader); - htmlExternal.append(htmlLoading); + const loadingEl = document.createElement('div'); + loadingEl.classList.add('flex-container', 'alignItemsCenter', 'justifyCenter', 'marginTop10', 'marginBot5'); + const loadingIcon = document.createElement('i'); + loadingIcon.classList.add('fa-solid', 'fa-spinner', 'fa-spin'); + const loadingSpan = document.createElement('span'); + loadingSpan.textContent = t`Loading third-party extensions... Please wait...`; + loadingEl.append(loadingIcon, loadingSpan); + + externalContainer.appendChild(loadingEl); const sortOrderKey = 'extensions_sortByName'; const sortByName = accountStorage.getItem(sortOrderKey) === 'true'; @@ -1063,16 +1297,16 @@ async function showExtensionsDetails() { let extensionsToToggle = []; extensions.forEach(value => { - const { isExternal, extensionHtml } = value; - const container = isExternal ? htmlExternal : htmlDefault; - container.append(extensionHtml); + const { isExternal, extensionElement } = value; + const container = isExternal ? externalContainer : defaultContainer; + container.appendChild(extensionElement); }); - const html = $('
') + const extensionsMenu = $('
') .addClass('extensions_info') - .append(htmlErrors) - .append(htmlDefault) - .append(htmlExternal) + .append(errors) + .append(defaultContainer) + .append(externalContainer) .append(getModuleInformation()); { @@ -1098,23 +1332,24 @@ async function showExtensionsDetails() { const toggleAllExtensionsButton = document.createElement('div'); toggleAllExtensionsButton.classList.add('menu_button', 'menu_button_icon'); toggleAllExtensionsButton.title = t`Bulk toggle third-party extensions.`; - toggleAllExtensionsButton.innerHTML = ` - ${t`Toggle extensions`} -
- `; + const toggleAllLabel = document.createElement('span'); + toggleAllLabel.textContent = t`Toggle extensions`; + const toggleAllIcon = document.createElement('div'); + toggleAllIcon.classList.add('fa-solid', 'fa-circle-info', 'opacity50p'); + toggleAllExtensionsButton.append(toggleAllLabel, toggleAllIcon); const restoreBulkToggledExtensionsButton = document.createElement('div'); restoreBulkToggledExtensionsButton.classList.add('menu_button', 'menu_button_icon', 'fa-solid', 'fa-arrow-right-rotate', 'displayNone'); restoreBulkToggledExtensionsButton.title = t`Restore toggled extensions.\n\nIt does not restore extensions toggled individually.`; toggleAllExtensionsButton.addEventListener('click', () => { - extensionsToToggle = onToggleAllExtensions(extensionsToToggle, htmlExternal); + extensionsToToggle = onToggleAllExtensions(extensionsToToggle, $(externalContainer)); for (const extension of extensionsToToggle) { const { name } = extension; - htmlExternal - .find(`.extension_block[data-name="${name.replace('third-party', '')}"] .extension_toggle input`) + $(externalContainer) + .find(`.extension_block[data-name="${getNameSelector(name)}"] .extension_toggle input`) .off('click') .one('click', () => { extensionsToToggle = extensionsToToggle.filter(ext => ext.name !== name); @@ -1131,8 +1366,8 @@ async function showExtensionsDetails() { const { name } = extension; const isDisabled = extension_settings.disabledExtensions.includes(name); - htmlExternal - .find(`.extension_block[data-name="${name.replace('third-party', '')}"] .extension_toggle input`) + $(externalContainer) + .find(`.extension_block[data-name="${getNameSelector(name)}"] .extension_toggle input`) .prop('checked', !isDisabled) .toggleClass('toggle_enable', isDisabled) .toggleClass('toggle_disable', !isDisabled) @@ -1156,13 +1391,13 @@ async function showExtensionsDetails() { }); toolbar.append(updateAllButton, updateEnabledOnlyButton, flexExpander, sortOrderButton); - htmlExternal.find('.third_party_toolbar').append(restoreBulkToggledExtensionsButton, toggleAllExtensionsButton); - html.prepend(toolbar); + thirdPartyToolbar.append(restoreBulkToggledExtensionsButton, toggleAllExtensionsButton); + extensionsMenu.prepend(toolbar); } let waitingForSave = false; - const popup = new Popup(html, POPUP_TYPE.TEXT, '', { + const popup = new Popup(extensionsMenu, POPUP_TYPE.TEXT, '', { okButton: t`Close`, wide: true, large: true, @@ -1204,7 +1439,7 @@ async function showExtensionsDetails() { }); popupPromise = popup.show(); popup.content.scrollTop = initialScrollTop; - checkForUpdatesManual(sortFn, abortController).finally(() => htmlLoading.remove()); + checkForUpdatesManual(sortFn, abortController).finally(() => loadingEl.remove()); } catch (error) { toastr.error(t`Error loading extensions. See browser console for details.`); console.error(error); @@ -1214,7 +1449,6 @@ async function showExtensionsDetails() { abortController.abort(); } if (requiresReload) { - showLoader(); location.reload(); } } @@ -1307,6 +1541,8 @@ async function updateExtension(extensionName, quiet, { timeoutMs = null, abortCo toastr.success('Extension is already up to date'); } } else { + const fullExtensionName = extensionName.startsWith('third-party') ? extensionName : `third-party${extensionName}`; + await callExtensionHook(fullExtensionName, 'update'); toastr.success(t`Extension ${extensionName} updated to ${data.shortCommitHash}`, t`Reload the page to apply updates`); } } catch (error) { @@ -1323,6 +1559,7 @@ async function updateExtension(extensionName, quiet, { timeoutMs = null, abortCo * This function makes a POST request to '/api/extensions/delete' with the extension's name. * If the extension is deleted, it displays a success message. * Creates a popup for the user to confirm before delete. + * If the extension has a 'clean' hook, an optional checkbox to also run the cleanup is shown. */ async function onDeleteClick() { const extensionName = $(this).data('name'); @@ -1333,13 +1570,50 @@ async function onDeleteClick() { return; } - // use callPopup to create a popup for the user to confirm before delete - const confirmation = await callGenericPopup(t`Are you sure you want to delete ${extensionName}?`, POPUP_TYPE.CONFIRM, '', {}); + const hasCleanHook = hasExtensionHook(extensionName, 'clean'); + + /** @type {import('./popup.js').CustomPopupInput[]} */ + const customInputs = hasCleanHook ? [{ id: 'extension_delete_cleanup', label: t`Also clean up extension data`, defaultState: false }] : null; + + const popup = new Popup(t`Are you sure you want to delete ${escapeHtml(extensionName)}?`, POPUP_TYPE.CONFIRM, '', { customInputs }); + const confirmation = await popup.show(); if (confirmation === POPUP_RESULT.AFFIRMATIVE) { - await deleteExtension(extensionName); + const shouldClean = hasCleanHook && Boolean(popup.inputResults?.get('extension_delete_cleanup')); + await deleteExtension(extensionName, shouldClean); } } +/** + * Handles the click event for the clean button of an extension. + * Runs the extension's 'clean' hook after user confirmation, then reloads the page. + */ +async function onCleanClick() { + const extensionName = $(this).data('name'); + + const confirmation = await Popup.show.confirm(t`Clean extension data`, t`Are you sure you want to clean up data for ${escapeHtml(extensionName)}? This action cannot be undone.`); + if (!confirmation) { + return; + } + + await cleanExtension(extensionName); +} + +/** + * Runs the 'clean' hook for an extension and reloads the page. + * @param {string} extensionName Extension name (without 'third-party' prefix) + * @returns {Promise} + */ +async function cleanExtension(extensionName) { + const fullExtensionName = extensionName.startsWith('third-party') ? extensionName : `third-party${extensionName}`; + await callExtensionHook(fullExtensionName, 'clean'); + + // Clean might have updated settings, which could race with the page reload, so we'll force save here + await saveSettings(); + + toastr.success(t`Extension ${extensionName} data cleaned`); + delay(1000).then(() => location.reload()); +} + async function onBranchClick() { const extensionName = $(this).data('name'); const isCurrentUserAdmin = isAdmin(); @@ -1392,8 +1666,8 @@ async function onMoveClick() { const confirmationHeader = t`Move extension`; const confirmationText = source == 'global' - ? t`Are you sure you want to move ${extensionName} to your local extensions? This will make it available only for you.` - : t`Are you sure you want to move ${extensionName} to the global extensions? This will make it available for all users.`; + ? t`Are you sure you want to move ${escapeHtml(extensionName)} to your local extensions? This will make it available only for you.` + : t`Are you sure you want to move ${escapeHtml(extensionName)} to the global extensions? This will make it available for all users.`; const confirmation = await Popup.show.confirm(confirmationHeader, confirmationText); @@ -1442,8 +1716,17 @@ async function moveExtension(extensionName, source, destination) { /** * Deletes an extension via the API. * @param {string} extensionName Extension name to delete + * @param {boolean} [shouldClean=false] Whether to also run the 'clean' hook before deleting */ -export async function deleteExtension(extensionName) { +export async function deleteExtension(extensionName, shouldClean = false) { + const fullExtensionName = extensionName.startsWith('third-party') ? extensionName : `third-party${extensionName}`; + + if (shouldClean) { + await callExtensionHook(fullExtensionName, 'clean'); + } + + await callExtensionHook(fullExtensionName, 'delete'); + try { await fetch('/api/extensions/delete', { method: 'POST', @@ -1457,6 +1740,9 @@ export async function deleteExtension(extensionName) { console.error('Error:', error); } + // Delete or clean might have updated settings, which could race with the page reload, so we'll force save here + await saveSettings(); + toastr.success(t`Extension ${extensionName} deleted`); delay(1000).then(() => location.reload()); } @@ -1475,30 +1761,38 @@ async function getExtensionVersion(extensionName, abortController) { return null; } - const response = await fetch('/api/extensions/version', { - method: 'POST', - headers: getRequestHeaders(), - body: JSON.stringify({ - extensionName, - global: getExtensionType(extensionName) === 'global', - }), - signal: abortController?.signal, - }); + try { + const response = await fetch('/api/extensions/version', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + extensionName, + global: getExtensionType(extensionName) === 'global', + }), + signal: abortController?.signal, + }); - if (!response.ok) { - const text = await response.text(); - const normalized = stripCommandErrorPrefixes(text || response.statusText); - if (isGitHubRateLimitStatus(response.status) || isGitHubRateLimitMessage(normalized)) { - githubRateLimitStopper.trip(); - cancelQueuedVersionChecks(); - abortController?.abort(); - return null; + if (!response.ok) { + const text = await response.text(); + const normalized = stripCommandErrorPrefixes(text || response.statusText); + if (isGitHubRateLimitStatus(response.status) || isGitHubRateLimitMessage(normalized)) { + githubRateLimitStopper.trip(); + cancelQueuedVersionChecks(); + abortController?.abort(); + return null; + } + + throw new Error(normalized || response.statusText); } - throw new Error(normalized || response.statusText); + const data = await response.json(); + return data; + } catch (error) { + if (error instanceof Error && error.name === 'AbortError') { + return null; + } + throw error; } - - return response.json(); } /** @@ -1563,7 +1857,7 @@ async function switchExtensionBranch(extensionName, isGlobal, branch) { return; } - toastr.success(t`Extension ${extensionName} switched to ${branch}`); + toastr.success(t`Extension ${extensionName} switched to ${branch}`, t`Reload the page to apply updates`); await loadExtensionSettings({}, false, false); void showExtensionsDetails(); } catch (error) { @@ -1575,7 +1869,8 @@ async function switchExtensionBranch(extensionName, isGlobal, branch) { * Installs a third-party extension via the API. * @param {string} url Extension repository URL * @param {boolean} global Is the extension global? - * @returns {Promise} + * @param {string} [branch] Optional branch to install, if not provided the default branch will be used + * @returns {Promise} True if the extension was installed successfully, false otherwise */ const GITHUB_ONLY_ERROR_TOKEN = 'only github repositories are supported'; @@ -1599,6 +1894,49 @@ async function showGithubOnlyRepositoryPopup() { } export async function installExtension(url, global, branch = '') { + try { + const parsedUrl = new URL(url); + if (!['http:', 'https:'].includes(parsedUrl.protocol)) { + throw new Error('Invalid URL protocol'); + } + + // Normalize the URL (resolve relative paths, remove redundant segments, etc.) + url = parsedUrl.href; + } catch (error) { + console.error('Invalid URL:', error); + toastr.error(t`Only valid HTTP and HTTPS URLs are allowed.`, t`Invalid URL`); + return false; + } + + if (!isOfficialExtension(url)) { + const extensionInstallationWarningKey = 'extensionInstallationWarningShown'; + if (accountStorage.getItem(extensionInstallationWarningKey)) { + console.debug('Bypassed URL check for third-party extension (account preference).', url); + } else { + let dismissWarning = false; + const confirmation = await Popup.show.confirm( + t`Install a third-party extension?`, + await renderTemplateAsync('thirdPartyExtensionWarning'), + { + customInputs: [{ id: 'dontAskAgain', type: 'checkbox', label: t`Don't show this warning again`, defaultState: false }], + onClose: (popup) => { + if (!popup.result) { + return; + } + dismissWarning = Boolean(popup.inputResults?.get('dontAskAgain') ?? false); + }, + okButton: t`Yes, install it`, + cancelButton: t`No, cancel`, + }); + if (!confirmation) { + return false; + } + if (dismissWarning) { + accountStorage.setItem(extensionInstallationWarningKey, '1'); + } + } + } + console.debug('Extension installation started', url); toastr.info(t`Please wait...`, t`Installing extension`); @@ -1635,14 +1973,21 @@ export async function installExtension(url, global, branch = '') { toastr.warning(getExtensionInstallToastMessage(text || request.statusText), t`Extension installation failed`, { timeOut: 5000 }); console.error('Extension installation failed', request.status, request.statusText, text); - return; + return false; } const response = await request.json(); - toastr.success(t`Extension '${response.display_name}' by ${response.author} (version ${response.version}) has been installed successfully!`, t`Extension installation successful`); + toastr.success(t`Extension '${response.display_name}' has been installed successfully!`, t`Extension installation successful`); console.debug(`Extension "${response.display_name}" has been installed successfully at ${response.extensionPath}`); await loadExtensionSettings({}, false, false); await eventSource.emit(event_types.EXTENSION_SETTINGS_LOADED, response); + + if (response.folderName) { + const extensionName = `third-party/${response.folderName}`; + await callExtensionHook(extensionName, 'install'); + } + + return true; } /** @@ -1809,8 +2154,12 @@ async function checkForUpdatesManual(sortFn, abortController) { const promise = enqueueVersionCheck(async () => { try { const data = await getExtensionVersion(externalId, abortController); - const extensionBlock = document.querySelector(`.extension_block[data-name="${externalId}"]`); - if (extensionBlock && data) { + if (!data) { + return; + } + const selector = getNameSelector(externalId, { prefix: '' }); + const extensionBlock = document.querySelector(`.extension_block[data-name="${selector}"]`); + if (extensionBlock) { if (data.isUpToDate === false) { const buttonElement = extensionBlock.querySelector('.btn_update'); if (buttonElement) { @@ -1840,6 +2189,18 @@ async function checkForUpdatesManual(sortFn, abortController) { } } + const authorElement = extensionBlock.querySelector('.extension_author'); + if (authorElement) { + const author = getAuthorFromUrl(origin) || EMPTY_AUTHOR; + if (author.name) { + const icon = document.createElement('i'); + icon.classList.add('fa-solid', 'fa-at', 'fa-xs'); + const name = document.createElement('span'); + name.textContent = author.name; + authorElement.append(icon, name); + } + } + const versionElement = extensionBlock.querySelector('.extension_version'); if (versionElement) { versionElement.textContent += ` (${branch}-${commitHash.substring(0, 7)})`; @@ -1900,7 +2261,10 @@ async function checkForExtensionUpdates(force) { const promise = enqueueVersionCheck(async () => { try { const data = await getExtensionVersion(id.replace('third-party', ''), abortController); - if (data && !data.isUpToDate) { + if (!data) { + return; + } + if (!data.isUpToDate) { updatesAvailable.push(manifest.display_name); } } catch (error) { @@ -2002,6 +2366,18 @@ export async function runGenerationInterceptors(chat, contextSize, type) { return aborted; } +/** + * Sentinel value that signals a field should be completely removed (unset) + * from the character card rather than being set to any value. Pass this as + * the `value` argument to {@link writeExtensionField} or + * {@link writeExtensionFieldBulk} to delete the key entirely. + * + * Using `null` as a value will set the field to `null` (the key remains). + * Using this sentinel will delete the key from the character card. + * @type {string} + */ +export const UNSET_VALUE = '__@@UNSET@@__'; + /** * Writes a field to the character's data extensions object. * @param {number|string} characterId Index in the character array @@ -2016,13 +2392,23 @@ export async function writeExtensionField(characterId, key, value) { console.warn('Character not found', characterId); return; } - const path = `data.extensions.${key}`; - setValueByPath(character, path, value); + const extensionPath = `data.extensions.${key}`; + const isUnset = value === UNSET_VALUE; + + if (isUnset) { + deleteValueByPath(character, extensionPath); + } else { + setValueByPath(character, extensionPath, value); + } // Process JSON data if (character.json_data) { const jsonData = JSON.parse(character.json_data); - setValueByPath(jsonData, path, value); + if (isUnset) { + deleteValueByPath(jsonData, extensionPath); + } else { + setValueByPath(jsonData, extensionPath, value); + } character.json_data = JSON.stringify(jsonData); // Make sure the data doesn't get lost when saving the current character @@ -2051,6 +2437,107 @@ export async function writeExtensionField(characterId, key, value) { } } +/** + * @typedef {object} BulkExtensionFieldResult + * @property {string[]} updated Avatar filenames that were successfully updated + * @property {string[]} skipped Avatar filenames skipped (filter didn't match or unreadable) + * @property {string[]} failed Avatar filenames where the update failed + */ + +/** + * Writes (or deletes) an extension field for multiple characters in a single + * bulk request. Unlike {@link writeExtensionField}, this sends one API call + * for all characters, and the server processes them in parallel. + * + * When `value` is {@link UNSET_VALUE} the extension key is **deleted** from + * each matching character card. Passing `null` sets the field to `null` + * (the key is preserved). + * + * @param {string[]|null} avatars Avatar filenames to update. Pass `null` or an + * empty array to target **all** characters in the user's character directory. + * @param {string} key Extension field name (e.g. "greeting_tools") + * @param {any} value Field value, `null` to set null, or + * {@link UNSET_VALUE} to delete the key entirely + * @param {object} [options={}] Optional settings + * @param {string} [options.filterPath] Dot-path filter — the server will only + * update characters where this path is present and not `undefined`; + * `null` still counts as a match. Useful when the frontend has shallow + * character data and cannot pre-filter. + * Defaults to `data.extensions.` when unsetting, so deletion requests + * automatically skip characters where the field is missing/`undefined`. + * @returns {Promise} Summary of the bulk operation + */ +export async function writeExtensionFieldBulk(avatars, key, value, { filterPath } = {}) { + const context = getContext(); + const extensionPath = `data.extensions.${key}`; + const isUnset = value === UNSET_VALUE; + + // Build the server request + const requestBody = { + avatars: Array.isArray(avatars) && avatars.length > 0 ? avatars : [], + data: { + data: { + extensions: { + [key]: value, + }, + }, + }, + }; + + // Default filter: when unsetting, only touch characters that have the field + const resolvedFilterPath = filterPath ?? (isUnset ? extensionPath : undefined); + if (resolvedFilterPath) { + requestBody.filter = { path: resolvedFilterPath }; + } + + const mergeResponse = await fetch('/api/characters/merge-attributes', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify(requestBody), + }); + + if (!mergeResponse.ok) { + console.error('Bulk extension field update failed', mergeResponse.statusText); + return { updated: [], skipped: [], failed: [] }; + } + + /** @type {BulkExtensionFieldResult} */ + const result = await mergeResponse.json(); + + // Sync in-memory character objects for successfully updated characters + const updatedSet = new Set(result.updated); + for (const character of context.characters) { + if (!character || !updatedSet.has(character.avatar)) continue; + + if (isUnset) { + deleteValueByPath(character, extensionPath); + } else { + setValueByPath(character, extensionPath, value); + } + + // Keep json_data in sync + if (character.json_data) { + const jsonData = JSON.parse(character.json_data); + if (isUnset) { + deleteValueByPath(jsonData, extensionPath); + } else { + setValueByPath(jsonData, extensionPath, value); + } + character.json_data = JSON.stringify(jsonData); + } + } + + // If the currently active character was updated, sync the hidden input + if (context.characterId !== undefined) { + const activeChar = context.characters[context.characterId]; + if (activeChar && updatedSet.has(activeChar.avatar) && activeChar.json_data) { + $('#character_json_data').val(activeChar.json_data); + } + } + + return result; +} + /** * Prompts the user to enter the Git URL of the extension to import. * After obtaining the Git URL, makes a POST request to '/api/extensions/install' to import the extension. @@ -2097,6 +2584,39 @@ export async function openThirdPartyExtensionMenu(suggestUrl = '') { await installExtension(url, global, branchName); } +/** + * Sentinel value representing an empty author, used when author information cannot be extracted from a URL. + * @type {{name: string, url: string}} + */ +export const EMPTY_AUTHOR = Object.freeze({ + name: '', + url: '', +}); + +/** + * Extracts the repository author from a given URL. + * @param {string} url - The URL of the repository. + * @returns {{name: string, url: string}} Object containing the author's name and URL, or empty strings if not found. + */ +export function getAuthorFromUrl(url) { + const result = structuredClone(EMPTY_AUTHOR); + + try { + const parsedUrl = new URL(url); + const pathSegments = parsedUrl.pathname.split('/').filter(s => s.length > 0); + + // TODO: Handle non-GitHub URLs if needed + if (parsedUrl.host === 'github.com' && pathSegments.length >= 2) { + result.name = pathSegments[0]; + result.url = `${parsedUrl.protocol}//${parsedUrl.hostname}/${result.name}`; + } + } catch (error) { + console.debug('Error parsing URL:', error); + } + + return result; +} + export async function initExtensions() { eventSource.once(event_types.APP_READY, () => { void (async () => { diff --git a/src/scripts/extensions/attachments/index.js b/src/scripts/extensions/attachments/index.js index 0583d4d9..31e858fd 100644 --- a/src/scripts/extensions/attachments/index.js +++ b/src/scripts/extensions/attachments/index.js @@ -243,7 +243,7 @@ function handleCharacterRename(oldAvatar, newAvatar) { } } -jQuery(async () => { +export async function init() { eventSource.on(event_types.APP_READY, cleanUpAttachments); eventSource.on(event_types.CHARACTER_DELETED, cleanUpCharacterAttachments); eventSource.on(event_types.CHARACTER_RENAMED, handleCharacterRename); @@ -407,4 +407,4 @@ jQuery(async () => { }), ], })); -}); +} diff --git a/src/scripts/extensions/attachments/manage-button.html b/src/scripts/extensions/attachments/manage-button.html index f051e2aa..555cc8ce 100644 --- a/src/scripts/extensions/attachments/manage-button.html +++ b/src/scripts/extensions/attachments/manage-button.html @@ -1,6 +1,6 @@ -
+
Open Data Bank
diff --git a/src/scripts/extensions/attachments/manifest.json b/src/scripts/extensions/attachments/manifest.json index 27f55f77..0b2fdf02 100644 --- a/src/scripts/extensions/attachments/manifest.json +++ b/src/scripts/extensions/attachments/manifest.json @@ -7,5 +7,8 @@ "css": "style.css", "author": "Cohee1207", "version": "1.0.0", - "homePage": "https://github.com/SillyTavern/SillyTavern" + "homePage": "https://github.com/SillyTavern/SillyTavern", + "hooks": { + "activate": "init" + } } diff --git a/src/scripts/extensions/gallery/index.js b/src/scripts/extensions/gallery/index.js index 665cd4c7..6a581cbc 100644 --- a/src/scripts/extensions/gallery/index.js +++ b/src/scripts/extensions/gallery/index.js @@ -791,15 +791,34 @@ async function listGalleryCommand(args) { const items = await getGalleryItems(url); return JSON.stringify(items.map(it => it.src)); - } catch (err) { console.error(err); } return JSON.stringify([]); } +function addGalleryWandButton() { + const showGalleryContainer = document.getElementById('gallery_wand_container') || document.getElementById('extensionsMenu'); + if (!(showGalleryContainer instanceof HTMLElement)) { + return; + } + const showGalleryButton = document.createElement('div'); + showGalleryButton.id = 'show_gallery_wand_button'; + showGalleryButton.classList.add('list-group-item', 'flex-container', 'flexGap5'); + const showGalleryIcon = document.createElement('div'); + showGalleryIcon.classList.add('fa-solid', 'fa-sd-card', 'extensionsMenuExtensionButton'); + const showGalleryText = document.createElement('span'); + showGalleryText.textContent = translate('Show Gallery'); + showGalleryButton.appendChild(showGalleryIcon); + showGalleryButton.appendChild(showGalleryText); + showGalleryButton.addEventListener('click', () => { + showCharGallery(); + }); + showGalleryContainer.appendChild(showGalleryButton); +} + // On extension load, ensure the settings are initialized -(function () { +export async function init() { initSettings(); eventSource.on(event_types.CHARACTER_RENAMED, (oldAvatar, newAvatar) => { const context = SillyTavern.getContext(); @@ -830,4 +849,5 @@ async function listGalleryCommand(args) { text: translate('Show Gallery'), }), ); -})(); + addGalleryWandButton(); +} diff --git a/src/scripts/extensions/gallery/manifest.json b/src/scripts/extensions/gallery/manifest.json index 0ba46c13..8fcf0e83 100644 --- a/src/scripts/extensions/gallery/manifest.json +++ b/src/scripts/extensions/gallery/manifest.json @@ -8,5 +8,8 @@ "css": "style.css", "author": "City-Unit", "version": "1.5.0", - "homePage": "https://github.com/SillyTavern/SillyTavern" + "homePage": "https://github.com/SillyTavern/SillyTavern", + "hooks": { + "activate": "init" + } } diff --git a/src/scripts/extensions/token-counter/index.js b/src/scripts/extensions/token-counter/index.js index 4ebe3d92..ed952867 100644 --- a/src/scripts/extensions/token-counter/index.js +++ b/src/scripts/extensions/token-counter/index.js @@ -101,7 +101,7 @@ async function doCount() { return count; } -jQuery(() => { +export function init() { const buttonHtml = `
` + @@ -115,5 +115,4 @@ jQuery(() => { returns: 'number of tokens', helpString: 'Counts the number of tokens in the current chat.', })); - -}); +} diff --git a/src/scripts/extensions/token-counter/manifest.json b/src/scripts/extensions/token-counter/manifest.json index b05dd6e3..caa0ad15 100644 --- a/src/scripts/extensions/token-counter/manifest.json +++ b/src/scripts/extensions/token-counter/manifest.json @@ -7,5 +7,8 @@ "css": "style.css", "author": "Cohee#1207", "version": "1.0.0", - "homePage": "https://github.com/SillyTavern/SillyTavern" + "homePage": "https://github.com/SillyTavern/SillyTavern", + "hooks": { + "activate": "init" + } } diff --git a/src/scripts/extensions/translate/index.js b/src/scripts/extensions/translate/index.js index 58de3683..9ff1c234 100644 --- a/src/scripts/extensions/translate/index.js +++ b/src/scripts/extensions/translate/index.js @@ -707,7 +707,7 @@ const handleMessageReasoningDelete = createEventHandler(removeReasoningDisplayTe globalThis.translate = translate; -jQuery(async () => { +export async function init() { const html = await renderExtensionTemplateAsync('translate', 'index'); const buttonHtml = await renderExtensionTemplateAsync('translate', 'buttons'); @@ -801,4 +801,4 @@ jQuery(async () => { }, returns: ARGUMENT_TYPE.STRING, })); -}); +} diff --git a/src/scripts/extensions/translate/manifest.json b/src/scripts/extensions/translate/manifest.json index b40a2aed..9ec8c918 100644 --- a/src/scripts/extensions/translate/manifest.json +++ b/src/scripts/extensions/translate/manifest.json @@ -7,5 +7,8 @@ "css": "style.css", "author": "Cohee#1207", "version": "1.0.0", - "homePage": "https://github.com/SillyTavern/SillyTavern" + "homePage": "https://github.com/SillyTavern/SillyTavern", + "hooks": { + "activate": "init" + } } diff --git a/src/scripts/f-localStorage.js b/src/scripts/f-localStorage.js index 50b1fe50..67c72837 100644 --- a/src/scripts/f-localStorage.js +++ b/src/scripts/f-localStorage.js @@ -13,7 +13,6 @@ export function SaveLocal(target, val) { export function LoadLocal(target) { console.debug('LoadLocal -- ' + target); return localStorage.getItem(target); - } /** * @deprecated THIS FUNCTION IS OBSOLETE. DO NOT USE diff --git a/src/scripts/filters.js b/src/scripts/filters.js index eb5329d8..932f2475 100644 --- a/src/scripts/filters.js +++ b/src/scripts/filters.js @@ -76,7 +76,6 @@ export const fuzzySearchCategories = Object.freeze({ * data = filterHelper.applyFilters(data); */ export class FilterHelper { - /** * Cache fuzzy search weighting scores for re-usability, sorting and stuff * @@ -290,6 +289,16 @@ export class FilterHelper { return this.filterDataByState(data, state, isFolder); } + /** + * Filters an array of entities based on a tri-state filter value. + * SELECTED keeps entities where filterFunc returns true; EXCLUDED removes them; UNDEFINED returns data unchanged. + * @param {any[]} data The data to filter + * @param {FilterState|string} state The tri-state filter value (SELECTED, EXCLUDED, or UNDEFINED) + * @param {Function} filterFunc A predicate function applied to each entity + * @param {object} [options] Options object + * @param {boolean} [options.includeFolders=false] If true, entities with type 'tag' always pass through + * @returns {any[]} The filtered data + */ filterDataByState(data, state, filterFunc, { includeFolders = false } = {}) { if (isFilterState(state, FILTER_STATES.SELECTED)) { return data.filter(entity => filterFunc(entity) || (includeFolders && entity.type == 'tag')); @@ -329,8 +338,7 @@ export class FilterHelper { // We can filter easily by checking if we have saved a score const score = _this.getScore(FILTER_TYPES.SEARCH, `${entity.type}.${entity.id}`); return score !== undefined; - } - else { + } else { // Compare insensitive and without accents return includesIgnoreCaseAndAccents(entity.item?.name, searchValue); } @@ -416,7 +424,7 @@ export class FilterHelper { typeScores.set(uid, score); } this.scoreCache.set(type, typeScores); - console.debug('search scores chached', type, typeScores); + console.debug('search scores cached', type, typeScores); } /** diff --git a/src/scripts/input-md-formatting.js b/src/scripts/input-md-formatting.js index 5b69fb79..ce038927 100644 --- a/src/scripts/input-md-formatting.js +++ b/src/scripts/input-md-formatting.js @@ -59,7 +59,8 @@ export function initInputMarkdown() { let cursorShift = charsToAdd.length; let selectedTextandPossibleFormatting = textarea.value.substring(start - possiblePreviousFormattingMargin, end + possiblePreviousFormattingMargin).trim(); - if (isTextSelected) { //if text is selected + if (isTextSelected) { + //if text is selected selectedText = textarea.value.substring(start, end); if (selectedTextandPossibleFormatting === charsToAdd + selectedText + charsToAdd) { // If the selected text is already formatted, remove the formatting @@ -90,7 +91,8 @@ export function initInputMarkdown() { textarea.focus(); document.execCommand('insertText', false, charsToAdd + selectedText + charsToAdd + possibleAddedSpace); } - } else {// No text is selected + } else { + // No text is selected //check 1 character before and after the cursor for non-space characters if (beforeCaret !== ' ' && afterCaret !== ' ' && afterCaret !== '' && beforeCaret !== '') { //look for caret in the middle of a word @@ -116,7 +118,6 @@ export function initInputMarkdown() { } if (charsToAdd + discoveredWord + charsToAdd === discoveredWordWithPossibleFormatting) { - // Replace the expanded selection with the original discovered word textarea.focus(); document.execCommand('insertText', false, discoveredWord); @@ -126,8 +127,6 @@ export function initInputMarkdown() { textarea.focus(); document.execCommand('insertText', false, charsToAdd + discoveredWord + charsToAdd); } - - } else { //caret is not inside a word, so just add the formatting textarea.focus(); textarea.setSelectionRange(start, end); diff --git a/src/scripts/keyboard.js b/src/scripts/keyboard.js index 3142e090..077feb49 100644 --- a/src/scripts/keyboard.js +++ b/src/scripts/keyboard.js @@ -8,6 +8,7 @@ const interactableSelectors = [ '.inline-drawer-icon', // Buttons/icons inside the drawer menus '.paginationjs-pages li a', // Pagination buttons '.group_select, .character_select, .bogus_folder_select', // Cards to select char, group or folder in character list and other places + '.swipe_picker_block', // Swipe picker entries in the swipe history popup '.avatar-container', // Persona list blocks '.tag .tag_remove', // Remove button in removable tags '.bg_example', // Background elements in the background menu @@ -20,6 +21,11 @@ const interactableSelectors = [ '.select2_choice_clickable+span.select2-container .select2-selection__choice__display', // select2 control elements if they are meant to be clickable '.avatar_load_preview', // Char display avatar selection '.bg_tabs_list .bg_tab_button', // Background tabs + '.select_chat_block', // The blocks to select a past chat in the past chats menu + '.select_chat_block .exportRawChatButton', // Export raw chat button in the past chats menu + '.select_chat_block .exportChatButton', // Export chat button in the past chats menu + '.select_chat_block .PastChat_cross', // Delete chat button in the past chats menu + '.select_chat_block .renameChatButton', // The button to rename a past chat in the past chats menu ]; if (CSS.supports('selector(:has(*))')) { diff --git a/src/scripts/logit-bias.js b/src/scripts/logit-bias.js index f1061def..35ad9885 100644 --- a/src/scripts/logit-bias.js +++ b/src/scripts/logit-bias.js @@ -117,11 +117,8 @@ export function getLogitBiasListResult(biasPreset, tokenizerType, getBiasObject) if (text.startsWith('{') && text.endsWith('}')) { const tokens = getTextTokens(tokenizerType, text.slice(1, -1)); result.push(getBiasObject(entry.value, tokens)); - } - - - // Raw token ids, JSON serialized - else if (text.startsWith('[') && text.endsWith(']')) { + } else if (text.startsWith('[') && text.endsWith(']')) { + // Raw token ids, JSON serialized try { const tokens = JSON.parse(text); @@ -133,11 +130,8 @@ export function getLogitBiasListResult(biasPreset, tokenizerType, getBiasObject) } catch (err) { console.log(`Failed to parse logit bias token list: ${text}`, err); } - } - - - // Text with a leading space - else { + } else { + // Text with a leading space const biasText = ` ${text}`; const tokens = getTextTokens(tokenizerType, biasText); result.push(getBiasObject(entry.value, tokens)); diff --git a/src/scripts/macros.js b/src/scripts/macros.js index 4026a353..cbe17426 100644 --- a/src/scripts/macros.js +++ b/src/scripts/macros.js @@ -1,5 +1,5 @@ import { Handlebars, moment, seedrandom, droll } from '../lib.js'; -import { chat, chat_metadata, main_api, getMaxContextSize, getCurrentChatId, substituteParams, eventSource, event_types, extension_prompts } from '../script.js'; +import { chat, chat_metadata, main_api, getMaxPromptTokens, getMaxContextTokens, getMaxResponseTokens, getCurrentChatId, substituteParams, eventSource, event_types, extension_prompts } from '../script.js'; import { timestampToMoment, isDigitsOnly, getStringHash, escapeRegex, uuidv4 } from './utils.js'; import { textgenerationwebui_banned_in_macros } from './textgen-settings.js'; import { getInstructMacros } from './instruct-mode.js'; @@ -58,10 +58,11 @@ export class MacrosParser { * * @param {string} method * @param {string} replacement + * @param {IArguments} [methodArgs=null] * @returns {void} */ - static #logDeprecated(method, replacement) { - console.warn(`[DEPRECATED] MacrosParser.${method} is deprecated and will be removed in a future version. Use ${replacement} instead.`); + static #logDeprecated(method, replacement, methodArgs = null) { + console.warn(`[DEPRECATED] MacrosParser.${method} is deprecated and will be removed in a future version. Use ${replacement} instead. Arguments:`, (methodArgs ?? 'none')); } /** @@ -155,7 +156,7 @@ export class MacrosParser { * @returns {string|MacroFunction|undefined} The macro value */ static get(key) { - MacrosParser.#logDeprecated('get', 'macros.registry.getMacro (from scripts/macros/macro-system.js)'); + MacrosParser.#logDeprecated('get', 'macros.registry.getMacro (from scripts/macros/macro-system.js)', arguments); return MacrosParser.#macros.get(key); } @@ -165,7 +166,7 @@ export class MacrosParser { * @returns {boolean} True if the macro is registered, false otherwise */ static has(key) { - MacrosParser.#logDeprecated('has', 'macros.registry.hasMacro (from scripts/macros/macro-system.js)'); + MacrosParser.#logDeprecated('has', 'macros.registry.hasMacro (from scripts/macros/macro-system.js)', arguments); if (power_user.experimental_macro_engine) { return macroSystem.registry.hasMacro(key); } @@ -180,7 +181,7 @@ export class MacrosParser { * @param {string} [description] Optional description of the macro */ static registerMacro(key, value, description = '') { - MacrosParser.#logDeprecated('registerMacro', 'macros.registry.registerMacro (from scripts/macros/macro-system.js) or substituteParams({ dynamicMacros })'); + MacrosParser.#logDeprecated('registerMacro', 'macros.registry.registerMacro (from scripts/macros/macro-system.js) or substituteParams({ dynamicMacros })', arguments); if (typeof key !== 'string') { throw new Error('Macro key must be a string'); } @@ -223,7 +224,7 @@ export class MacrosParser { * @param {string} key Macro name (key) */ static unregisterMacro(key) { - MacrosParser.#logDeprecated('unregisterMacro', 'macros.registry.unregisterMacro (from scripts/macros/macro-system.js)'); + MacrosParser.#logDeprecated('unregisterMacro', 'macros.registry.unregisterMacro (from scripts/macros/macro-system.js)', arguments); if (typeof key !== 'string') { throw new Error('Macro key must be a string'); } @@ -639,7 +640,12 @@ export function evaluateMacros(content, env, postProcessFn) { * @type {Macro[]} */ const postEnvMacros = [ - { regex: /{{maxPrompt}}/gi, replace: () => String(getMaxContextSize()) }, + { regex: /{{maxPrompt}}/gi, replace: () => String(getMaxPromptTokens()) }, + { regex: /{{maxPromptTokens}}/gi, replace: () => String(getMaxPromptTokens()) }, + { regex: /{{maxContext}}/gi, replace: () => String(getMaxContextTokens()) }, + { regex: /{{maxContextTokens}}/gi, replace: () => String(getMaxContextTokens()) }, + { regex: /{{maxResponse}}/gi, replace: () => String(getMaxResponseTokens()) }, + { regex: /{{maxResponseTokens}}/gi, replace: () => String(getMaxResponseTokens()) }, { regex: /{{lastMessage}}/gi, replace: () => getLastMessage() }, { regex: /{{lastMessageId}}/gi, replace: () => String(getLastMessageId() ?? '') }, { regex: /{{lastUserMessage}}/gi, replace: () => getLastUserMessage() }, @@ -648,6 +654,7 @@ export function evaluateMacros(content, env, postProcessFn) { { regex: /{{firstDisplayedMessageId}}/gi, replace: () => String(getFirstDisplayedMessageId() ?? '') }, { regex: /{{lastSwipeId}}/gi, replace: () => String(getLastSwipeId() ?? '') }, { regex: /{{currentSwipeId}}/gi, replace: () => String(getCurrentSwipeId() ?? '') }, + { regex: /{{allChatRange}}/gi, replace: () => chat.length === 0 ? '' : `0-${chat.length - 1}` }, { regex: /{{reverse:(.+?)}}/gi, replace: (_, str) => Array.from(str).reverse().join('') }, { regex: /\{\{\/\/([\s\S]*?)\}\}/gm, replace: () => '' }, { regex: /{{time}}/gi, replace: () => moment().format('LT') }, diff --git a/src/scripts/macros/definitions/chat-macros.js b/src/scripts/macros/definitions/chat-macros.js index ebe8e9ec..0dd179ee 100644 --- a/src/scripts/macros/definitions/chat-macros.js +++ b/src/scripts/macros/definitions/chat-macros.js @@ -66,6 +66,18 @@ export function registerChatMacros() { returnType: MacroValueType.INTEGER, handler: () => String(getCurrentSwipeId() ?? ''), }); + + MacroRegistry.registerMacro('allChatRange', { + category: MacroCategory.CHAT, + description: 'Range of all message IDs in the chat (e.g. "0-10"). Empty string if the chat is empty.', + returns: 'Range string from 0 to last message ID, or empty string.', + handler: () => { + if (!Array.isArray(chat) || chat.length === 0) { + return ''; + } + return `0-${chat.length - 1}`; + }, + }); } function getLastMessageId({ exclude_swipe_in_propress = true, filter = null } = {}) { diff --git a/src/scripts/macros/definitions/core-macros.js b/src/scripts/macros/definitions/core-macros.js index 8f81d1dd..c4be45f9 100644 --- a/src/scripts/macros/definitions/core-macros.js +++ b/src/scripts/macros/definitions/core-macros.js @@ -1,5 +1,5 @@ import { seedrandom, droll } from '../../../lib.js'; -import { chat_metadata, main_api, getMaxContextSize, extension_prompts, getCurrentChatId } from '../../../script.js'; +import { chat_metadata, main_api, getMaxPromptTokens, getMaxContextTokens, getMaxResponseTokens, extension_prompts, getCurrentChatId } from '../../../script.js'; import { getStringHash, isFalseBoolean } from '../../utils.js'; import { textgenerationwebui_banned_in_macros } from '../../textgen-settings.js'; import { inject_ids } from '../../constants.js'; @@ -232,13 +232,34 @@ export function registerCoreMacros() { handler: () => (/** @type {HTMLTextAreaElement} */(document.querySelector('#send_textarea')))?.value ?? '', }); - // {{maxPrompt}} -> max context size + // {{maxPrompt}} -> max context size (context minus response) MacroRegistry.registerMacro('maxPrompt', { + aliases: [{ alias: 'maxPromptTokens', visible: true }], category: MacroCategory.STATE, description: 'Maximum prompt context size.', returns: 'Maximum prompt context size.', returnType: MacroValueType.INTEGER, - handler: () => String(getMaxContextSize()), + handler: () => String(getMaxPromptTokens()), + }); + + // {{maxContext}} -> max context token limit + MacroRegistry.registerMacro('maxContext', { + aliases: [{ alias: 'maxContextTokens', visible: true }], + category: MacroCategory.STATE, + description: 'Maximum context token limit.', + returns: 'Maximum context token limit.', + returnType: MacroValueType.INTEGER, + handler: () => String(getMaxContextTokens()), + }); + + // {{maxResponse}} -> max response token limit + MacroRegistry.registerMacro('maxResponse', { + aliases: [{ alias: 'maxResponseTokens', visible: true }], + category: MacroCategory.STATE, + description: 'Maximum response token limit.', + returns: 'Maximum response token limit.', + returnType: MacroValueType.INTEGER, + handler: () => String(getMaxResponseTokens()), }); // String utilities diff --git a/src/scripts/macros/definitions/env-macros.js b/src/scripts/macros/definitions/env-macros.js index ded9ced1..a6256609 100644 --- a/src/scripts/macros/definitions/env-macros.js +++ b/src/scripts/macros/definitions/env-macros.js @@ -140,6 +140,30 @@ export function registerEnvMacros() { handler: ({ env }) => env.character.creatorNotes ?? '', }); + MacroRegistry.registerMacro('charFirstMessage', { + aliases: [{ alias: 'greeting' }], + category: MacroCategory.CHARACTER, + unnamedArgs: [ + { + name: 'index', + optional: true, + defaultValue: '0', + type: MacroValueType.INTEGER, + description: '0-based index. 0 (default) returns the main greeting, 1 and up return alternate greetings.', + }, + ], + description: 'The character\'s first message / greeting. Optionally specify an index to access alternate greetings.', + returns: 'Character greeting at the given index, or empty string if out of bounds.', + exampleUsage: ['{{greeting}}', '{{greeting::0}}', '{{greeting::1}}'], + handler: ({ env, unnamedArgs: [index] }) => { + const i = Number(index ?? 0); + if (i === 0) return env.character.firstMessage ?? ''; + const altGreetings = env.character.alternateGreetings; + if (!Array.isArray(altGreetings)) return ''; + return altGreetings[i - 1] ?? ''; + }, + }); + // Character version macros (legacy variants and documented {{charVersion}}) MacroRegistry.registerMacro('charVersion', { aliases: [ diff --git a/src/scripts/macros/engine/MacroCstWalker.js b/src/scripts/macros/engine/MacroCstWalker.js index 412d4ac1..7cf87646 100644 --- a/src/scripts/macros/engine/MacroCstWalker.js +++ b/src/scripts/macros/engine/MacroCstWalker.js @@ -1001,9 +1001,8 @@ class MacroCstWalker { endOffset: element.endOffset ?? element.startOffset, token: element, }); - } - // Handle nested CstNode (macro or argument) - else if ('children' in element) { + } else if ('children' in element) { + // Handle nested CstNode (macro or argument) const nestedChildren = element.children || {}; const nestedEnd = /** @type {IToken?} */ ((nestedChildren['Macro.End'] || [])[0]); const nestedStart = /** @type {IToken?} */ ((nestedChildren['Macro.Start'] || [])[0]); diff --git a/src/scripts/macros/engine/MacroEnv.types.js b/src/scripts/macros/engine/MacroEnv.types.js index 40de21cf..0d42af34 100644 --- a/src/scripts/macros/engine/MacroEnv.types.js +++ b/src/scripts/macros/engine/MacroEnv.types.js @@ -38,6 +38,8 @@ * @property {string} [charDepthPrompt] * @property {string} [creatorNotes] * @property {string} [version] + * @property {string} [firstMessage] + * @property {string[]} [alternateGreetings] */ /** diff --git a/src/scripts/macros/engine/MacroEnvBuilder.js b/src/scripts/macros/engine/MacroEnvBuilder.js index 99a7b060..e25cc65d 100644 --- a/src/scripts/macros/engine/MacroEnvBuilder.js +++ b/src/scripts/macros/engine/MacroEnvBuilder.js @@ -109,10 +109,19 @@ class MacroEnvBuilder { ['version', 'version'], ['charDepthPrompt', 'charDepthPrompt'], ['creatorNotes', 'creatorNotes'], + ['firstMessage', 'firstMessage'], + ['alternateGreetings', 'alternateGreetings'], ]); for (const [envKey, fieldKey] of fieldMappings) { Object.defineProperty(env.character, envKey, { - get() { return fields[fieldKey] || ''; }, + get() { + const value = fields[fieldKey]; + // alternateGreetings should default to [] instead of '' + if (envKey === 'alternateGreetings') { + return Array.isArray(value) ? value : []; + } + return value || ''; + }, enumerable: true, configurable: true, }); diff --git a/src/scripts/reasoning.js b/src/scripts/reasoning.js index 026f640e..74183c54 100644 --- a/src/scripts/reasoning.js +++ b/src/scripts/reasoning.js @@ -16,7 +16,7 @@ import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandE import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; import { textgen_types, textgenerationwebui_settings } from './textgen-settings.js'; import { applyStreamFadeIn } from './util/stream-fadein.js'; -import { copyText, escapeRegex, isFalseBoolean, isTrueBoolean, setDatasetProperty, trimSpaces } from './utils.js'; +import { copyText, escapeRegex, isFalseBoolean, isTrueBoolean, setDatasetProperty, stringToRange, trimSpaces } from './utils.js'; /** * @typedef {object} ReasoningTemplate @@ -31,7 +31,7 @@ import { copyText, escapeRegex, isFalseBoolean, isTrueBoolean, setDatasetPropert */ export const reasoning_templates = []; -export const DEFAULT_REASONING_TEMPLATE = 'DeepSeek'; +export const DEFAULT_REASONING_TEMPLATE = 'Think XML'; /** * @type {Record>} List of UI elements for reasoning settings @@ -115,12 +115,14 @@ export function extractReasoningFromData(data, { case chat_completion_sources.XAI: return data?.choices?.[0]?.message?.reasoning_content ?? ''; case chat_completion_sources.OPENROUTER: - return data?.choices?.[0]?.message?.reasoning ?? ''; + return data?.choices?.[0]?.message?.reasoning + ?? data?.choices?.[0]?.message?.reasoning_content + ?? ''; case chat_completion_sources.MAKERSUITE: case chat_completion_sources.VERTEXAI: return data?.responseContent?.parts?.filter(part => part.thought)?.map(part => part.text)?.join('\n\n') ?? ''; case chat_completion_sources.CLAUDE: - return data?.content?.find(part => part.type === 'thinking')?.thinking ?? ''; + return data?.content?.filter(part => part.type === 'thinking')?.map(part => part.thinking)?.join('\n\n') ?? ''; case chat_completion_sources.MISTRALAI: return data?.choices?.[0]?.message?.content?.[0]?.thinking?.map(part => part.text)?.filter(x => x)?.join('\n\n') ?? ''; case chat_completion_sources.AIMLAPI: @@ -132,6 +134,7 @@ export function extractReasoningFromData(data, { case chat_completion_sources.NANOGPT: case chat_completion_sources.SILICONFLOW: case chat_completion_sources.ZAI: + case chat_completion_sources.WORKERS_AI: case chat_completion_sources.CUSTOM: { return data?.choices?.[0]?.message?.reasoning_content ?? data?.choices?.[0]?.message?.reasoning @@ -865,7 +868,6 @@ function selectReasoningTemplateCallback(args, name) { UI.$select.val(foundName).trigger('change'); !quiet && toastr.success(`Reasoning template "${foundName}" selected`); return foundName; - } function registerReasoningSlashCommands() { @@ -1008,6 +1010,44 @@ function registerReasoningSlashCommands() { : parsedReasoning.reasoning; }, })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'reasoning-format', + aliases: ['format-reasoning'], + returns: 'formatted string', + helpString: t`Formats reasoning and content into a single string using Reasoning Formatting settings. Useful for preparing text that can be parsed with /reasoning-parse.`, + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'reasoning', + description: 'The reasoning/thinking text to format', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: true, + }), + ], + unnamedArgumentList: [ + SlashCommandArgument.fromProps({ + description: 'The main content text', + typeList: [ARGUMENT_TYPE.STRING], + isRequired: false, + }), + ], + callback: (args, value) => { + const reasoning = String(args?.reasoning ?? ''); + const content = String(value ?? ''); + + if (!power_user.reasoning.prefix || !power_user.reasoning.suffix) { + toastr.warning(t`Both prefix and suffix must be set in the Reasoning Formatting settings.`, t`Reasoning Format`); + return ''; + } + + if (!reasoning) { + toastr.warning(t`Reasoning argument is required.`, t`Reasoning Format`); + return ''; + } + + const { formatted } = formatReasoning(reasoning, content); + return formatted; + }, + })); SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'reasoning-template', aliases: ['reasoning-formatting', 'reasoning-preset'], @@ -1044,6 +1084,80 @@ function registerReasoningSlashCommands() {
`, })); + + /** + * Gets the reasoning details elements for a message range. + * @param {string} value Unnamed argument value (message ID or range) + * @returns {JQuery|null} The reasoning details elements, or null if not found + */ + function getReasoningDetailsElements(value) { + const range = value ? stringToRange(String(value), 0, chat.length - 1) : { start: chat.length - 1, end: chat.length - 1 }; + if (!range) { + toastr.warning(t`Invalid message ID or range: ${value}`); + return null; + } + const selector = Array.from({ length: range.end - range.start + 1 }, (_, i) => + `#chat [mesid="${range.start + i}"] .mes_reasoning_details`, + ).join(','); + const details = $(selector); + if (details.length === 0) { + toastr.warning(t`No reasoning blocks found for the specified messages.`); + return null; + } + return details; + } + + const reasoningVisibilityArgs = [ + SlashCommandArgument.fromProps({ + description: 'Message ID or range (e.g. 0-10). If not provided, the last message is used.', + typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], + enumProvider: commonEnumProviders.messages(), + }), + ]; + + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'reasoning-collapse', + aliases: ['collapse-reasoning'], + helpString: t`Collapse the reasoning block of a message or range of messages.`, + unnamedArgumentList: reasoningVisibilityArgs, + callback: (_args, value) => { + const details = getReasoningDetailsElements(value.toString()); + if (details) details.removeAttr('open'); + return ''; + }, + })); + + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'reasoning-expand', + aliases: ['expand-reasoning'], + helpString: t`Expand the reasoning block of a message or range of messages.`, + unnamedArgumentList: reasoningVisibilityArgs, + callback: (_args, value) => { + const details = getReasoningDetailsElements(value.toString()); + if (details) details.attr('open', ''); + return ''; + }, + })); + + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'reasoning-toggle', + aliases: ['toggle-reasoning'], + helpString: t`Toggle the reasoning block of a message or range of messages. Expanded blocks will be collapsed, and collapsed blocks will be expanded.`, + unnamedArgumentList: reasoningVisibilityArgs, + callback: (_args, value) => { + const details = getReasoningDetailsElements(value.toString()); + if (!details) return ''; + details.each(function () { + const $el = $(this); + if ($el.attr('open') !== undefined) { + $el.removeAttr('open'); + } else { + $el.attr('open', ''); + } + }); + return ''; + }, + })); } function registerReasoningMacros() { @@ -1335,6 +1449,36 @@ export function parseReasoningFromString(str, { strict = true } = {}, template = } } +/** + * Formats reasoning and content into a string using the reasoning template. + * This is the inverse of parseReasoningFromString. + * @typedef {Object} FormattedReasoning + * @property {string} formatted The formatted string with reasoning wrapped in prefix/suffix + * @property {string} contentOnly The content without reasoning + * @param {string} reasoning The reasoning/thinking text + * @param {string} content The main content/response text + * @param {ReasoningTemplate} [template=null] Optional template to use. Defaults to power_user.reasoning + * @returns {FormattedReasoning} Object containing both formatted (reasoning + content) and contentOnly + */ +export function formatReasoning(reasoning, content, template = null) { + template = template ?? power_user.reasoning; + + // If no reasoning provided, return content only + if (!reasoning || !template.prefix || !template.suffix) { + return { formatted: content, contentOnly: content }; + } + + // Substitute macros in template parts + const prefix = substituteParams(template.prefix || ''); + const suffix = substituteParams(template.suffix || ''); + const separator = substituteParams(template.separator || ''); + + // Build the formatted string: prefix + reasoning + suffix + separator + content + const formatted = `${prefix}${reasoning}${suffix}${separator}${content}`; + + return { formatted, contentOnly: content }; +} + /** * Parse reasoning in an array of swipe strings if auto-parsing is enabled. * @param {string[]} swipes Array of swipe strings diff --git a/src/scripts/request-compression.js b/src/scripts/request-compression.js new file mode 100644 index 00000000..2b1090a8 --- /dev/null +++ b/src/scripts/request-compression.js @@ -0,0 +1,131 @@ +import { gzip } from '/lib.js'; + +/** + * @type {RequestCompressionConfig} + * + * @typedef {Object} RequestCompressionConfig + * @property {boolean} enabled Whether request compression is enabled. + * @property {number} minPayloadSize Minimum payload size in bytes to trigger compression. + * @property {number} maxPayloadSize Hard upper payload size limit for compression. + * @property {number} timeout Timeout for request compression in milliseconds. + */ +const requestCompressionConfig = { + enabled: false, + minPayloadSize: 0, + maxPayloadSize: 0, + timeout: 0, +}; + +/** + * Sets the configuration for request compression from the server. + * @param {RequestCompressionConfig} config Configuration object for request compression + */ +export function setRequestCompressionConfig(config) { + Object.assign(requestCompressionConfig, (config ?? {})); +} + +/** + * Compresses a Uint8Array using gzip. + * @param {Uint8Array} input Uint8Array to compress + * @returns {{ promise: Promise>, terminate: () => void }} Gzip-compressed Uint8Array promise and a terminate function. + */ +function gzipBuffer(input) { + let terminate = () => {}; + const promise = new Promise((resolve, reject) => { + try { + terminate = gzip(input, (error, compressed) => { + if (error) { + reject(error); + return; + } + + resolve(new Uint8Array(compressed)); + }); + } catch (error) { + reject(error); + } + }); + return { promise, terminate }; +} + +/** + * Wraps a promise with a timeout, rejecting if the promise does not settle within the specified time. + * Note: timeout does not cancel the underlying compression task; it only stops waiting for it. + * @param {Promise} promise Promise to wrap with a timeout + * @param {number} timeoutMs Timeout in milliseconds + * @param {string} label Used for error message if timeout occurs + * @returns {Promise} Resolves with the original promise's value if it settles in time, otherwise rejects with a timeout error + * @template T Type of the promise's resolved value + */ +async function withTimeout(promise, timeoutMs, label) { + let timeoutId = null; + const timeoutPromise = new Promise((_, reject) => { + timeoutId = setTimeout(() => reject(new Error(`${label}_timeout`)), timeoutMs); + }); + + try { + return await Promise.race([promise, timeoutPromise]); + } finally { + if (timeoutId !== null) { + clearTimeout(timeoutId); + } + } +} + +/** + * Compresses a fetch request using gzip when supported and worthwhile. + * Compression is skipped when feature-toggle is disabled, body is too small, + * body is not a string, or compression fails/timeouts. + * + * @param {RequestInit} request fetch request parameters + * @returns {Promise} A request init object that may include gzip-compressed body + */ +export async function compressRequest(request) { + const plainRequest = { ...request }; + const requestBody = plainRequest?.body; + + if (!requestCompressionConfig.enabled) { + return plainRequest; + } + + if (!requestBody || typeof requestBody !== 'string') { + return plainRequest; + } + + const textEncoder = new TextEncoder(); + const encodedBody = textEncoder.encode(requestBody); + const bodySize = encodedBody.byteLength; + const minBytes = Number(requestCompressionConfig.minPayloadSize) || 0; + const maxBytes = Number(requestCompressionConfig.maxPayloadSize) || 0; + + if (bodySize < minBytes || (maxBytes > 0 && bodySize > maxBytes)) { + return plainRequest; + } + + const { promise, terminate } = gzipBuffer(encodedBody); + + try { + const compressedBody = await withTimeout( + promise, + requestCompressionConfig.timeout, + 'compress_fflate_gzip', + ); + + if (!compressedBody || compressedBody.byteLength >= bodySize) { + return plainRequest; + } + + const headers = new Headers(plainRequest.headers ?? {}); + headers.set('Content-Encoding', 'gzip'); + + return { + ...plainRequest, + headers, + body: compressedBody, + }; + } catch (error) { + terminate(); + console.warn('Failed to compress request body, using plain request.', error); + return plainRequest; + } +} diff --git a/src/scripts/samplerSelect.js b/src/scripts/samplerSelect.js index a6a0b297..dedcfef9 100644 --- a/src/scripts/samplerSelect.js +++ b/src/scripts/samplerSelect.js @@ -203,7 +203,6 @@ function setSamplerListListeners() { console.log(samplerName, relatedDOMElement.data(SELECT_SAMPLER.DATA), shouldDisplay); }); - } function isElementVisibleInDOM(element) { @@ -221,7 +220,7 @@ async function listSamplers(main_api, arrayOnly = false) { let availableSamplers; if (main_api === 'textgenerationwebui') { availableSamplers = TGsamplerNames; - const valuesToRemove = new Set(['streaming', 'bypass_status_check', 'custom_model', 'legacy_api', 'extensions']); + const valuesToRemove = new Set(['streaming', 'bypass_status_check', 'custom_model', 'generic_model', 'openrouter_allow_fallbacks', 'legacy_api', 'extensions']); availableSamplers = availableSamplers.filter(sampler => !valuesToRemove.has(sampler)); availableSamplers.sort(); } @@ -247,9 +246,7 @@ async function listSamplers(main_api, arrayOnly = false) { if (prioritizeManualSamplerSelect) { finalState = isManuallyActivated; - } - - else if (!isInDefaultState) { + } else if (!isInDefaultState) { finalState = displayModified === SELECT_SAMPLER.SHOWN; customColor = finalState ? forcedOnColoring : forcedOffColoring; } diff --git a/src/scripts/secrets.js b/src/scripts/secrets.js index 001c8415..86a91b49 100644 --- a/src/scripts/secrets.js +++ b/src/scripts/secrets.js @@ -504,7 +504,7 @@ function authorizeOpenRouter() { * Checks if the OpenRouter authorization code is present in the URL, and if so, exchanges it for an API key. * @returns {Promise} */ -async function checkOpenRouterAuth() { +export async function checkOpenRouterAuth() { const params = new URLSearchParams(location.search); const source = params.get('source'); if (source === 'openrouter') { diff --git a/src/scripts/showdown-underscore.js b/src/scripts/showdown-underscore.js index 34c763c0..38eacbf8 100644 --- a/src/scripts/showdown-underscore.js +++ b/src/scripts/showdown-underscore.js @@ -9,7 +9,7 @@ export const markdownUnderscoreExt = () => { return [{ type: 'output', regex: new RegExp('(]*)?>[\\s\\S]*?<\\/code>|]*)?>[\\s\\S]*?<\\/style>)|\\b(? or