diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index f7be5281..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "root": true, - "extends": ["eslint:recommended", "plugin:vue/recommended", "prettier"], - "env": { - "browser": true, - "commonjs": true, - "es2021": true - }, - "parser": "vue-eslint-parser", - "parserOptions": { - "parser": "@babel/eslint-parser", - "ecmaVersion": "latest", - "sourceType": "module", - "ecmaFeatures": { - "impliedStrict": true, - "jsx": true - }, - "requireConfigFile": false, - "babelOptions": { - "parserOpts": { - "plugins": ["importAssertions"] - } - } - }, - "globals": { - "CefSharp": "readonly", - "VRCX": "readonly", - "VRCXStorage": "readonly", - "SQLite": "readonly", - "LogWatcher": "readonly", - "Discord": "readonly", - "AppApi": "readonly", - "AppApiVr": "readonly", - "SharedVariable": "readonly", - "WebApi": "readonly", - "AssetBundleManager": "readonly", - "WINDOWS": "readonly", - "LINUX": "readonly" - }, - "rules": { - "no-console": 0, - "no-control-regex": 0, - "no-empty": [ - "error", - { - "allowEmptyCatch": true - } - ], - "no-var": "warn", - "prefer-const": "warn", - "no-loop-func": 0, - "vars-on-top": 0, - "object-curly-spacing": ["error", "always"], - "require-atomic-updates": 0, - "no-unused-vars": 1, - "vue/require-default-prop": 0, - "vue/no-mutating-props": 1, - "vue/no-v-text-v-html-on-component": 1 - } -} diff --git a/.gitignore b/.gitignore index aacaf387..28341702 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ obj1/ .idea/ *.log *.DotSettings.user -Installer/version_define.nsh \ No newline at end of file +.vs/ +Installer/version_define.nsh +bun.lock diff --git a/DBMerger/DBMerger.csproj b/DBMerger/DBMerger.csproj index e8d5acba..99e91aef 100644 --- a/DBMerger/DBMerger.csproj +++ b/DBMerger/DBMerger.csproj @@ -43,7 +43,7 @@ - + diff --git a/DBMerger/Merger.cs b/DBMerger/Merger.cs index cbcb909d..4bf1bc7d 100644 --- a/DBMerger/Merger.cs +++ b/DBMerger/Merger.cs @@ -1,5 +1,4 @@ using NLog; -using NLog.Fluent; using SQLite; using System; using System.Collections.Generic; diff --git a/DBMerger/Program.cs b/DBMerger/Program.cs index 65709259..194dc648 100644 --- a/DBMerger/Program.cs +++ b/DBMerger/Program.cs @@ -168,10 +168,8 @@ namespace DBMerger { FileName = "DBMerger.log", Layout = "${longdate} [${level:uppercase=true:padding=-5}] ${logger:padding=-20} - ${message} ${exception:format=tostring}", - ArchiveFileName = Path.Combine("DBMerger_Logs", "DBMerger.{#}.log"), - ArchiveNumbering = ArchiveNumberingMode.DateAndSequence, + ArchiveSuffixFormat = "{1:yyyy-MM-dd.HH-mm-ss}", ArchiveOldFileOnStartup = true, - ConcurrentWrites = true, KeepFileOpen = true, AutoFlush = true, Encoding = System.Text.Encoding.UTF8 diff --git a/Dotnet/AppApi/Cef/AppApiVr.cs b/Dotnet/AppApi/Cef/AppApiVr.cs index 0b0eebc3..97be0745 100644 --- a/Dotnet/AppApi/Cef/AppApiVr.cs +++ b/Dotnet/AppApi/Cef/AppApiVr.cs @@ -19,18 +19,18 @@ namespace VRCX { // Create Instance before Cef tries to bind it } - + public void VrInit() { if (MainForm.Instance?.Browser != null && !MainForm.Instance.Browser.IsLoading && MainForm.Instance.Browser.CanExecuteJavascriptInMainFrame) - MainForm.Instance.Browser.ExecuteScriptAsync("$app.vrInit", ""); + MainForm.Instance.Browser.ExecuteScriptAsync("$app.store.vr.vrInit", ""); } - + public void ToggleSystemMonitor(bool enabled) { SystemMonitor.Instance.Start(enabled); } - + /// /// Returns the current CPU usage as a percentage. /// @@ -39,7 +39,7 @@ namespace VRCX { return SystemMonitor.Instance.CpuUsage; } - + /// /// Returns an array of arrays containing information about the connected VR devices. /// Each sub-array contains the type of device and its current state @@ -49,7 +49,7 @@ namespace VRCX { return Program.VRCXVRInstance.GetDevices(); } - + /// /// Returns the number of milliseconds that the system has been running. /// @@ -58,7 +58,7 @@ namespace VRCX { return SystemMonitor.Instance.UpTime; } - + /// /// Returns the current language of the operating system. /// @@ -67,7 +67,7 @@ namespace VRCX { return CultureInfo.CurrentCulture.ToString(); } - + /// /// Returns the file path of the custom user js file, if it exists. /// @@ -80,7 +80,7 @@ namespace VRCX output = filePath; return output; } - + public bool IsRunningUnderWine() { return Wine.GetIfWine(); diff --git a/Dotnet/AppApi/Cef/GameHandler.cs b/Dotnet/AppApi/Cef/GameHandler.cs index 7b8f4b4a..d635e3b8 100644 --- a/Dotnet/AppApi/Cef/GameHandler.cs +++ b/Dotnet/AppApi/Cef/GameHandler.cs @@ -47,7 +47,7 @@ namespace VRCX // TODO: fix this throwing an exception for being called before the browser is ready. somehow it gets past the checks if (MainForm.Instance?.Browser != null && !MainForm.Instance.Browser.IsLoading && MainForm.Instance.Browser.CanExecuteJavascriptInMainFrame) - MainForm.Instance.Browser.ExecuteScriptAsync("$app.updateIsGameRunning", isGameRunning, isSteamVRRunning, isHmdAfk); + MainForm.Instance.Browser.ExecuteScriptAsync("$app.store.game.updateIsGameRunning", isGameRunning, isSteamVRRunning, isHmdAfk); } public override bool IsGameRunning() diff --git a/Dotnet/Cef/CefCustomDragHandler.cs b/Dotnet/Cef/CefCustomDragHandler.cs index 4218c126..dc0abb5f 100644 --- a/Dotnet/Cef/CefCustomDragHandler.cs +++ b/Dotnet/Cef/CefCustomDragHandler.cs @@ -24,9 +24,10 @@ namespace VRCX dragData.Dispose(); return true; } + + if (MainForm.Instance?.Browser != null && !MainForm.Instance.Browser.IsLoading && MainForm.Instance.Browser.CanExecuteJavascriptInMainFrame) + MainForm.Instance.Browser.ExecuteScriptAsync("$app.store.vrcx.dragEnterCef", file); - // forgive me father for i have sinned once again - Program.AppApiInstance.ExecuteAppFunction("dragEnterCef", file); dragData.Dispose(); return false; } diff --git a/Dotnet/Cef/CefCustomRequestHandler.cs b/Dotnet/Cef/CefCustomRequestHandler.cs new file mode 100644 index 00000000..df6ca0ff --- /dev/null +++ b/Dotnet/Cef/CefCustomRequestHandler.cs @@ -0,0 +1,74 @@ +// Copyright(c) 2019-2025 pypy, Natsumi and individual contributors. +// All rights reserved. +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . + +using System.Security.Cryptography.X509Certificates; +using CefSharp; +using NLog; + +namespace VRCX +{ + public class CustomRequestHandler : IRequestHandler + { + private readonly Logger _logger = LogManager.GetCurrentClassLogger(); + + public bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect) + { + if (Program.LaunchDebug || + request.Url.StartsWith("file://vrcx/") || + request.Url.StartsWith("chrome-extension://")) + return false; + + _logger.Error("Blocking navigation to: {Url}", request.Url); + return true; + } + + public void OnDocumentAvailableInMainFrame(IWebBrowser chromiumWebBrowser, IBrowser browser) + { + } + + public bool OnOpenUrlFromTab(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, + WindowOpenDisposition targetDisposition, bool userGesture) + { + _logger.Debug("Blocking OnOpenUrlFromTab: {TargetUrl}", + targetUrl); + + return true; + } + + public IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, + IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling) + { + return null; + } + + public bool GetAuthCredentials(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, bool isProxy, string host, + int port, string realm, string scheme, IAuthCallback callback) + { + return false; + } + + public bool OnCertificateError(IWebBrowser chromiumWebBrowser, IBrowser browser, CefErrorCode errorCode, string requestUrl, + ISslInfo sslInfo, IRequestCallback callback) + { + return true; + } + + public bool OnSelectClientCertificate(IWebBrowser chromiumWebBrowser, IBrowser browser, bool isProxy, string host, int port, + X509Certificate2Collection certificates, ISelectClientCertificateCallback callback) + { + return false; + } + + public void OnRenderViewReady(IWebBrowser chromiumWebBrowser, IBrowser browser) + { + } + + public void OnRenderProcessTerminated(IWebBrowser chromiumWebBrowser, IBrowser browser, CefTerminationStatus status, + int errorCode, string errorMessage) + { + } + } +} diff --git a/Dotnet/Cef/CefService.cs b/Dotnet/Cef/CefService.cs index a28ac5d9..3f9ee55a 100644 --- a/Dotnet/Cef/CefService.cs +++ b/Dotnet/Cef/CefService.cs @@ -25,7 +25,8 @@ namespace VRCX { RootCachePath = userDataDir, CachePath = Path.Join(userDataDir, "cache"), - LogSeverity = LogSeverity.Disable, + LogSeverity = Program.LaunchDebug ? LogSeverity.Verbose : LogSeverity.Error, + LogFile = Path.Join(Program.AppDataDirectory, "logs", "cef.log"), WindowlessRenderingEnabled = true, PersistSessionCookies = true, UserAgent = Program.Version, diff --git a/Dotnet/Cef/JavascriptBindings.cs b/Dotnet/Cef/JavascriptBindings.cs index 5a729b49..f5e89abd 100644 --- a/Dotnet/Cef/JavascriptBindings.cs +++ b/Dotnet/Cef/JavascriptBindings.cs @@ -8,7 +8,6 @@ namespace VRCX { repository.NameConverter = null; repository.Register("AppApi", Program.AppApiInstance); - repository.Register("SharedVariable", SharedVariable.Instance); repository.Register("WebApi", WebApi.Instance); repository.Register("VRCXStorage", VRCXStorage.Instance); repository.Register("SQLite", SQLiteLegacy.Instance); diff --git a/Dotnet/Cef/MainForm.cs b/Dotnet/Cef/MainForm.cs index 85e0e1d0..3b521eb3 100644 --- a/Dotnet/Cef/MainForm.cs +++ b/Dotnet/Cef/MainForm.cs @@ -5,8 +5,8 @@ // For a copy, see . using System; +using System.Diagnostics.CodeAnalysis; using System.Drawing; -using System.Net; using System.Reflection; using System.Windows.Forms; using CefSharp; @@ -15,6 +15,7 @@ using NLog; namespace VRCX { + [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] public partial class MainForm : WinformBase { public static MainForm Instance; @@ -50,30 +51,40 @@ namespace VRCX logger.Error(ex); } - Browser = new ChromiumWebBrowser("file://vrcx/index.html") + Browser = new ChromiumWebBrowser(Program.LaunchDebug ? "http://localhost:9000/index.html" : "file://vrcx/index.html") { DragHandler = new CustomDragHandler(), MenuHandler = new CustomMenuHandler(), DownloadHandler = new CustomDownloadHandler(), + RequestHandler = new CustomRequestHandler(), BrowserSettings = { DefaultEncoding = "UTF-8", }, Dock = DockStyle.Fill }; - - Browser.IsBrowserInitializedChanged += (A, B) => + Browser.IsBrowserInitializedChanged += (_, _) => { if (Program.LaunchDebug) Browser.ShowDevTools(); }; - - JavascriptBindings.ApplyAppJavascriptBindings(Browser.JavascriptObjectRepository); - Browser.ConsoleMessage += (_, args) => + Browser.AddressChanged += (_, addressChangedEventArgs) => { - logger.Debug(args.Message + " (" + args.Source + ":" + args.Line + ")"); + logger.Debug("Address changed: " + addressChangedEventArgs.Address); + }; + Browser.LoadingStateChanged += (_, loadingFailedEventArgs) => + { + if (loadingFailedEventArgs.IsLoading) + logger.Debug("Loading page"); + else + logger.Debug("Loaded page: " + loadingFailedEventArgs.Browser.MainFrame.Url); + }; + Browser.ConsoleMessage += (_, consoleMessageEventArgs) => + { + logger.Debug(consoleMessageEventArgs.Message + " (" + consoleMessageEventArgs.Source + ":" + consoleMessageEventArgs.Line + ")"); }; + JavascriptBindings.ApplyAppJavascriptBindings(Browser.JavascriptObjectRepository); Controls.Add(Browser); } diff --git a/Dotnet/Cef/WinformBase.cs b/Dotnet/Cef/WinformBase.cs index 4865e5b1..074c9620 100644 --- a/Dotnet/Cef/WinformBase.cs +++ b/Dotnet/Cef/WinformBase.cs @@ -12,7 +12,8 @@ namespace VRCX { protected override void OnHandleCreated(EventArgs e) { - WinformThemer.SetThemeToGlobal(this); + if (!DesignMode) + WinformThemer.SetThemeToGlobal(this); base.OnHandleCreated(e); } } diff --git a/Dotnet/Discord.cs b/Dotnet/Discord.cs index 0a4023ad..95518b64 100644 --- a/Dotnet/Discord.cs +++ b/Dotnet/Discord.cs @@ -4,14 +4,17 @@ // This work is licensed under the terms of the MIT license. // For a copy, see . +using System; using DiscordRPC; using System.Text; using System.Threading; +using NLog; namespace VRCX { public class Discord { + private readonly Logger _logger = LogManager.GetCurrentClassLogger(); public static readonly Discord Instance; private readonly ReaderWriterLockSlim m_Lock; private readonly RichPresence m_Presence; @@ -54,8 +57,9 @@ namespace VRCX { Update(); } - catch + catch (Exception ex) { + _logger.Error(ex, "Error updating Discord Rich Presence {Error}", ex.Message); } } } @@ -132,7 +136,7 @@ namespace VRCX } } - public void SetAssets(string largeKey, string largeText, string smallKey, string smallText, string partyId, int partySize, int partyMax, string buttonText, string buttonUrl, string appId) + public void SetAssets(string largeKey, string largeText, string smallKey, string smallText, string partyId, int partySize, int partyMax, string buttonText, string buttonUrl, string appId, int activityType = 0) { m_Lock.EnterWriteLock(); try @@ -153,6 +157,7 @@ namespace VRCX m_Presence.Party.ID = partyId; m_Presence.Party.Size = partySize; m_Presence.Party.Max = partyMax; + m_Presence.Type = (ActivityType)activityType; Button[] buttons = []; if (!string.IsNullOrEmpty(buttonUrl)) { @@ -207,6 +212,10 @@ namespace VRCX } } } + catch (Exception ex) + { + _logger.Error(ex, "Error setting timestamps in Discord Rich Presence {Error}", ex.Message); + } finally { m_Lock.ExitWriteLock(); diff --git a/Dotnet/IPC/IPCClient.cs b/Dotnet/IPC/IPCClient.cs index f1f04b29..c71228d9 100644 --- a/Dotnet/IPC/IPCClient.cs +++ b/Dotnet/IPC/IPCClient.cs @@ -90,7 +90,7 @@ namespace VRCX #if !LINUX if (MainForm.Instance?.Browser != null && !MainForm.Instance.Browser.IsLoading && MainForm.Instance.Browser.CanExecuteJavascriptInMainFrame) - MainForm.Instance.Browser.ExecuteScriptAsync("$app.ipcEvent", packet); + MainForm.Instance.Browser.ExecuteScriptAsync("$app.store.vrcx.ipcEvent", packet); #endif } diff --git a/Dotnet/LogWatcher.cs b/Dotnet/LogWatcher.cs index 818bcbea..2c4245ca 100644 --- a/Dotnet/LogWatcher.cs +++ b/Dotnet/LogWatcher.cs @@ -297,7 +297,7 @@ namespace VRCX m_LogQueue.Enqueue(logLine); #else if (MainForm.Instance != null && MainForm.Instance.Browser != null) - MainForm.Instance.Browser.ExecuteScriptAsync("$app.addGameLogEvent", logLine); + MainForm.Instance.Browser.ExecuteScriptAsync("$app.store.gameLog.addGameLogEvent", logLine); #endif } @@ -729,10 +729,9 @@ namespace VRCX return false; var data = line.Substring(offset + 13); - -#if !LINUX - WorldDBManager.Instance.ProcessLogWorldDataRequest(data); -#endif + + // PWI, deprecated + logger.Info("VRCX-World data: {0}", data); return true; } diff --git a/Dotnet/Overlay/VRCXVR.cs b/Dotnet/Overlay/VRCXVR.cs index cef37fee..8df95b70 100644 --- a/Dotnet/Overlay/VRCXVR.cs +++ b/Dotnet/Overlay/VRCXVR.cs @@ -188,13 +188,13 @@ namespace VRCX var dashboardHandle = 0UL; _wristOverlay = new OffScreenBrowser( - "file://vrcx/vr.html?1", + Program.LaunchDebug ? "http://localhost:9000/vr.html?1": "file://vrcx/vr.html?1", 512, 512 ); _hmdOverlay = new OffScreenBrowser( - "file://vrcx/vr.html?2", + Program.LaunchDebug ? "http://localhost:9000/vr.html?2": "file://vrcx/vr.html?2", 1024, 1024 ); diff --git a/Dotnet/Overlay/VRForm.cs b/Dotnet/Overlay/VRForm.cs index dee5300d..22a2bea7 100644 --- a/Dotnet/Overlay/VRForm.cs +++ b/Dotnet/Overlay/VRForm.cs @@ -26,6 +26,7 @@ namespace VRCX ) { DragHandler = new CefNoopDragHandler(), + RequestHandler = new CustomRequestHandler(), BrowserSettings = { DefaultEncoding = "UTF-8", diff --git a/Dotnet/PWI/WorldDBManager.cs b/Dotnet/PWI/WorldDBManager.cs deleted file mode 100644 index d08536ec..00000000 --- a/Dotnet/PWI/WorldDBManager.cs +++ /dev/null @@ -1,750 +0,0 @@ -using System.Linq; -using System.Text; -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Runtime.Serialization.Formatters.Binary; -using System.Threading.Tasks; -using CefSharp; -using Newtonsoft.Json; -using NLog; - -namespace VRCX -{ - public class WorldDBManager - { - public static readonly WorldDBManager Instance; - private readonly HttpListener listener; - private readonly WorldDatabase worldDB; - private static readonly Logger logger = LogManager.GetCurrentClassLogger(); - private const string WorldDBServerUrl = "http://127.0.0.1:22500/"; - - private string lastError = null; - private bool debugWorld = false; - - static WorldDBManager() - { - Instance = new WorldDBManager(); - } - - public WorldDBManager() - { - // http://localhost:22500 - listener = new HttpListener(); - listener.Prefixes.Add(WorldDBServerUrl); - - worldDB = new WorldDatabase(Path.Join(Program.AppDataDirectory, "VRCX-WorldData.db")); - } - - public void Init() - { - if (VRCXStorage.Instance.Get("VRCX_DisableWorldDatabase") == "true") - { - logger.Info("World database is disabled. Not starting."); - return; - } - - Task.Run(Start); - } - - private async Task Start() - { - // typing this in vr gonna kms - try - { - listener.Start(); - } - catch (HttpListenerException e) - { - logger.Error(e, "Failed to start HTTP listener. Is VRCX already running?"); - return; - } - - logger.Info("Listening for requests on {0}", listener.Prefixes.First()); - while (true) - { - var context = await listener.GetContextAsync(); - var request = context.Request; - var responseData = new WorldDataRequestResponse(false, null, null); - - try - { - if (MainForm.Instance?.Browser == null || MainForm.Instance.Browser.IsLoading || !MainForm.Instance.Browser.CanExecuteJavascriptInMainFrame) - { - logger.Error("Received a request to {0} while VRCX is still initializing the browser window. Responding with error 503.", request.Url); - - responseData.Error = "VRCX not yet initialized. Try again in a moment."; - responseData.StatusCode = 503; - responseData.ConnectionKey = null; - SendJsonResponse(context.Response, responseData); - continue; - }; - - logger.Debug("Received a request to '{0}'", request.Url); - - // TODO: Maybe an endpoint for getting a group of arbitrary keys by a group 'name'? eg; /getgroup?name=testgroup1 would return all keys with the column group set to 'testgroup1' - switch (request.Url.LocalPath) - { - case "/vrcx/data/init": - responseData = await HandleInitRequest(context); - SendJsonResponse(context.Response, responseData); - break; - case "/vrcx/data/get": - responseData = await HandleDataRequest(context); - SendJsonResponse(context.Response, responseData); - break; - case "/vrcx/data/getall": - responseData = await HandleAllDataRequest(context); - SendJsonResponse(context.Response, responseData); - break; - case "/vrcx/data/lasterror": - responseData.OK = lastError == null; - responseData.StatusCode = 200; - responseData.Data = lastError; - responseData.ConnectionKey = null; - lastError = null; - SendJsonResponse(context.Response, responseData); - break; - case "/vrcx/data/getbulk": - responseData = await HandleBulkDataRequest(context); - SendJsonResponse(context.Response, responseData); - break; - case "/vrcx/data/settings": - responseData = await HandleSetSettingsRequest(context); - SendJsonResponse(context.Response, responseData); - break; - case "/vrcx/status": - // Send a blank 200 response to indicate that the server is running. - context.Response.StatusCode = 200; - context.Response.Close(); - break; - default: - responseData.Error = "Invalid VRCX endpoint."; - responseData.StatusCode = 404; - responseData.ConnectionKey = null; - SendJsonResponse(context.Response, responseData); - break; - } - - if (context.Response.StatusCode != 200) - { - logger.Warn("Received a request to '{0}' that returned a non-successful response. Error: {1} - {2}", request.Url, responseData.StatusCode, responseData.Error); - } - } - catch (Exception ex) - { - logger.Error(ex, $"Exception while processing a request to endpoint '{request.Url}'."); - - responseData.Error = $"VRCX has encountered an exception while processing the url '{request.Url}': {ex.Message}"; - responseData.StatusCode = 500; - responseData.ConnectionKey = null; - SendJsonResponse(context.Response, responseData); - } - } - - } - - private async Task HandleSetSettingsRequest(HttpListenerContext context) - { - var request = context.Request; - - string worldId = await GetCurrentWorldID(); - string set = request.QueryString["set"]; - string value = request.QueryString["value"]; - - if (!TryInitializeWorld(worldId, out string connectionKey)) - { - return ConstructErrorResponse(500, "Failed to get/verify current world ID."); - } - - if (set != null && value != null) - { - switch (set) - { - case "externalReads": - if (request.QueryString["value"] == "true") - { - worldDB.SetWorldAllowExternalRead(worldId, true); - } - else if (request.QueryString["value"] == "false") - { - worldDB.SetWorldAllowExternalRead(worldId, false); - } - else - { - return ConstructErrorResponse(400, "Invalid value for 'externalReads' setting."); - } - break; - default: - return ConstructErrorResponse(400, "Invalid setting name."); - } - } - - return ConstructSuccessResponse(null, connectionKey); - } - - - /// - /// Handles an HTTP listener request to initialize a connection to the world db manager. - /// - /// The HTTP listener context object. - /// A object containing the response data. - private async Task HandleInitRequest(HttpListenerContext context) - { - var request = context.Request; - - if (request.QueryString["debug"] == "true") - { - debugWorld = true; - } - else if (request.QueryString["debug"] == "false") - { - debugWorld = false; - } - - string worldId = await GetCurrentWorldID(); - - if (TryInitializeWorld(worldId, out string connectionKey)) - { - logger.Info("Initialized a connection to the world database for world ID '{0}' with connection key {1}.", worldId, connectionKey); - return ConstructSuccessResponse(connectionKey, connectionKey); - } - else - { - return ConstructErrorResponse(500, "Failed to get/verify current world ID."); - } - } - - /// - /// Handles an HTTP listener request for data from the world database. - /// - /// The HTTP listener context object. - /// A object containing the response data. - private async Task HandleDataRequest(HttpListenerContext context) - { - var request = context.Request; - - var key = request.QueryString["key"]; - if (key == null) - { - return ConstructErrorResponse(400, "Missing key parameter."); - } - - var worldId = await GetCurrentWorldID(); - - if (!TryInitializeWorld(worldId, out string connectionKey)) - { - return ConstructErrorResponse(500, "Failed to get/verify current world ID."); - } - - var worldOverride = request.QueryString["world"]; - if (worldOverride == "global") - { - TryInitializeWorld(worldOverride, out connectionKey); - } - if (worldOverride != null && worldId != worldOverride) - { - var allowed = worldDB.GetWorldAllowExternalRead(worldOverride) || worldOverride == "global"; - if (!allowed) - { - return ConstructSuccessResponse(null, connectionKey); - } - - var otherValue = worldDB.GetDataEntry(worldOverride, key); - - logger.Debug("Serving a request for data with key '{0}' from world ID '{1}' requested by world ID '{2}' with connection key {3}.", key, worldOverride, worldId, connectionKey); - - // This value is intended to be null if the key doesn't exist. - return ConstructSuccessResponse(otherValue?.Value, connectionKey); - } - - var value = worldDB.GetDataEntry(worldId, key); - - logger.Debug("Serving a request for data with key '{0}' from world ID '{1}' with connection key {2}.", key, worldId, connectionKey); - // This value is intended to be null if the key doesn't exist. - return ConstructSuccessResponse(value?.Value, connectionKey); - } - - /// - /// Handles an HTTP listener request for all data from the world database for a given world. - /// - /// The HTTP listener context object. - /// A object containing the response data. - private async Task HandleAllDataRequest(HttpListenerContext context) - { - var request = context.Request; - var worldId = await GetCurrentWorldID(); - - if (!TryInitializeWorld(worldId, out string connectionKey)) - { - return ConstructErrorResponse(500, "Failed to get/verify current world ID."); - } - - var worldOverride = request.QueryString["world"]; - if (worldOverride == "global") - { - TryInitializeWorld(worldOverride, out connectionKey); - } - if (worldOverride != null && worldId != worldOverride) - { - var allowed = worldDB.GetWorldAllowExternalRead(worldOverride) || worldOverride == "global"; - if (!allowed) - { - return ConstructSuccessResponse(null, connectionKey); - } - - var otherEntries = worldDB.GetAllDataEntries(worldOverride); - - var otherData = new Dictionary(); - foreach (var entry in otherEntries) - { - otherData.Add(entry.Key, entry.Value); - } - - logger.Debug("Serving a request for all data ({0} entries) for world ID '{1}' requested by {2} with connection key {3}.", otherData.Count, worldOverride, worldId, connectionKey); - return ConstructSuccessResponse(JsonConvert.SerializeObject(otherData), connectionKey); - } - - var entries = worldDB.GetAllDataEntries(worldId); - - var data = new Dictionary(); - foreach (var entry in entries) - { - data.Add(entry.Key, entry.Value); - } - - logger.Debug("Serving a request for all data ({0} entries) for world ID '{1}' with connection key {2}.", data.Count, worldId, connectionKey); - return ConstructSuccessResponse(JsonConvert.SerializeObject(data), connectionKey); - } - - /// - /// Handles an HTTP listener request for bulk data from the world database. - /// - /// The HTTP listener context object. - /// A object containing the response data. - private async Task HandleBulkDataRequest(HttpListenerContext context) - { - var request = context.Request; - - var keys = request.QueryString["keys"]; - if (keys == null) - { - return ConstructErrorResponse(400, "Missing/invalid keys parameter."); - } - - var keyArray = keys.Split(','); - - var worldId = await GetCurrentWorldID(); - - if (!TryInitializeWorld(worldId, out string connectionKey)) - { - return ConstructErrorResponse(500, "Failed to get/verify current world ID."); - } - - var worldOverride = request.QueryString["world"]; - if (worldOverride == "global") - { - TryInitializeWorld(worldOverride, out connectionKey); - } - if (worldOverride != null && worldId != worldOverride) - { - var allowed = worldDB.GetWorldAllowExternalRead(worldOverride) || worldOverride == "global"; - if (!allowed) - { - return ConstructSuccessResponse(null, connectionKey); - } - - var otherEntries = worldDB.GetAllDataEntries(worldOverride); - - var otherData = new Dictionary(); - foreach (var entry in otherEntries) - { - otherData.Add(entry.Key, entry.Value); - } - - logger.Debug("Serving a request for all data ({0} entries) for world ID '{1}' requested by {2} with connection key {3}.", otherData.Count, worldOverride, worldId, connectionKey); - return ConstructSuccessResponse(JsonConvert.SerializeObject(otherData), connectionKey); - } - - var values = worldDB.GetDataEntries(worldId, keyArray).ToList(); - - // Build a dictionary of key/value pairs to send back. If a key doesn't exist in the database, the key will be included in the response as requested but with a null value. - var data = new Dictionary(); - for (int i = 0; i < keyArray.Length; i++) - { - string dataKey = keyArray[i]; - string dataValue = values?.Where(x => x.Key == dataKey).FirstOrDefault()?.Value; // Get the value from the list of data entries, if it exists, otherwise null - - data.Add(dataKey, dataValue); - } - - logger.Debug("Serving a request for bulk data with keys '{0}' from world ID '{1}' with connection key {2}.", keys, worldId, connectionKey); - return ConstructSuccessResponse(JsonConvert.SerializeObject(data), connectionKey); - } - - /// - /// Attempts to initialize a world with the given ID by generating a connection key and adding it to the world database if it does not already exist. - /// - /// The ID of the world to initialize. - /// The connection key generated for the world. - /// True if the world was successfully initialized, false otherwise. - private bool TryInitializeWorld(string worldId, out string connectionKey) - { - if (string.IsNullOrEmpty(worldId)) - { - connectionKey = null; - return false; - } - - var existsInDB = worldDB.DoesWorldExist(worldId); - - if (!existsInDB) - { - connectionKey = GenerateWorldConnectionKey(); - worldDB.AddWorld(worldId, connectionKey); - logger.Info("Added new world ID '{0}' with connection key '{1}' to the database.", worldId, connectionKey); - } - else - { - connectionKey = worldDB.GetWorldConnectionKey(worldId); - } - - return true; - } - - /// - /// Generates a unique identifier for a world connection request. - /// - /// A string representation of a GUID that can be used to identify the world on requests. - private string GenerateWorldConnectionKey() - { - if (debugWorld) return "12345"; - - // Ditched the old method of generating a short key, since we're just going with json anyway who cares about a longer identifier - // Since we can rely on this GUID being unique, we can use it to identify the world on requests instead of trying to keep track of the user's current world. - // I uhh, should probably make sure this is actually unique though. Just in case. I'll do that later. - return Guid.NewGuid().ToString(); - } - - /// - /// Gets the ID of the current world by evaluating a JavaScript function in the main browser instance. - /// - /// The ID of the current world as a string, or null if it could not be retrieved. - private async Task GetCurrentWorldID() - { - if (debugWorld) return "wrld_12345"; - - JavascriptResponse funcResult; - - try - { - funcResult = await MainForm.Instance.Browser.EvaluateScriptAsync("$app.API.actuallyGetCurrentLocation();", TimeSpan.FromSeconds(5)); - } - catch (Exception ex) - { - logger.Error(ex, "Failed to evaluate actuallyGetCurrentLocation JS function to get current world ID."); - return null; - } - - string worldId = funcResult?.Result?.ToString(); - - if (string.IsNullOrEmpty(worldId)) - { - // implement - // wait what was i going to do here again - // seriously i forgot, hope it wasn't important - logger.Warn("actuallyGetCurrentLocation returned null or empty."); - return null; - } - - return worldId; - } - - private WorldDataRequestResponse ConstructSuccessResponse(string data = null, string connectionKey = null) - { - var responseData = new WorldDataRequestResponse(true, null, null); - - responseData.StatusCode = 200; - responseData.Error = null; - responseData.OK = true; - responseData.Data = data; - responseData.ConnectionKey = connectionKey; - return responseData; - } - - private WorldDataRequestResponse ConstructErrorResponse(int statusCode, string error) - { - var responseData = new WorldDataRequestResponse(true, null, null); - - responseData.StatusCode = statusCode; - responseData.Error = error; - responseData.OK = false; - responseData.Data = null; - responseData.ConnectionKey = null; - - return responseData; - } - - /// - /// Sends a JSON response to an HTTP listener request with the specified response data and status code. - /// - /// The HTTP listener response object. - /// The response data to be serialized to JSON. - /// The HTTP status code to be returned. - /// The HTTP listener response object. - private HttpListenerResponse SendJsonResponse(HttpListenerResponse response, WorldDataRequestResponse responseData) - { - response.ContentType = "application/json"; - response.StatusCode = responseData.StatusCode; - response.AddHeader("Cache-Control", "no-cache"); - - // Use newtonsoft.json to serialize WorldDataRequestResponse to json - var json = JsonConvert.SerializeObject(responseData); - var buffer = System.Text.Encoding.UTF8.GetBytes(json); - response.ContentLength64 = buffer.Length; - response.OutputStream.Write(buffer, 0, buffer.Length); - response.Close(); - return response; - } - - /// - /// Processes a JSON request containing world data and logs it to the world database. - /// - /// The JSON request containing the world data. - public void ProcessLogWorldDataRequest(string json) - { - // Current format: - // { - // "requestType": "store", - // "connectionKey": "abc123", - // "key": "example_key", - // "value": "example_value" - // } - - // * I could rate limit the processing of this, but I don't think it's necessary. - // * At the amount of data you'd need to be spitting out to lag vrcx, you'd fill up the log file and lag out VRChat far before VRCX would have any issues; at least in my testing. - // As long as malicious worlds can't permanently *store* stupid amounts of unculled data, this is pretty safe with the 10MB cap. If a world wants to just fill up a users HDD with logs, they can do that already anyway. - - WorldDataRequest request; - - try // try to deserialize the json into a WorldDataRequest object - { - request = JsonConvert.DeserializeObject(json); - } - catch (JsonReaderException ex) - { - logger.Error(ex, json.ToString()); - this.lastError = ex.Message; - // invalid json - return; - } - catch (Exception ex) - { - logger.Error(ex, json.ToString()); - this.lastError = ex.Message; - // something else happened lol - return; - } - - if (string.IsNullOrEmpty(request.RequestType)) - { - logger.Warn("World tried to store data with no request type provided. Request: ", json); - this.lastError = "`requestType` is missing or null"; - return; - } - - // Make sure the connection key is a valid GUID. No point in doing anything else if it's not. - if (!debugWorld && !Guid.TryParse(request.ConnectionKey, out Guid _)) - { - logger.Warn("World tried to store data with an invalid GUID as a connection key '{0}'", request.ConnectionKey); - this.lastError = "Invalid GUID provided as connection key"; - // invalid guid - return; - } - - // Get the world ID from the connection key - string worldId = worldDB.GetWorldByConnectionKey(request.ConnectionKey); - - // Global override - if (request.ConnectionKey == "global") - { - worldId = "global"; - } - - // World ID is null, which means the connection key is invalid (or someone just deleted a world from the DB while VRCX was running lol). - if (worldId == null) - { - logger.Warn("World tried to store data under {0} with an invalid connection key {1}", request.Key, request.ConnectionKey); - this.lastError = "Invalid connection key"; - // invalid connection key - return; - } - - try - { - string requestType = request.RequestType.ToLower(); - switch (requestType) - { - case "store": - if (String.IsNullOrEmpty(request.Key)) - { - logger.Warn("World {0} tried to store data with no key provided", worldId); - this.lastError = "`key` is missing or null"; - return; - } - - if (request.Key.Length > 255) - { - logger.Warn("World {0} tried to store data with a key that was too long ({1}/256 characters)", worldId, request.Key.Length); - this.lastError = "`key` is too long. Keep it below <256 characters."; - return; - } - - if (request.Value == null) - { - logger.Warn("World {0} tried to store data under key {1} with null value", worldId, request.Key); - this.lastError = "`value` is null"; - return; - } - - StoreWorldData(worldId, request.Key, request.Value); - - break; - case "delete": - if (String.IsNullOrEmpty(request.Key)) - { - logger.Warn("World {0} tried to delete data with no key provided", worldId); - this.lastError = "`key` is missing or null"; - return; - } - - - DeleteWorldData(worldId, request.Key); - break; - case "delete-all": - - logger.Info("World {0} requested to delete all data.", worldId); - - - worldDB.DeleteAllDataEntriesForWorld(worldId); - worldDB.UpdateWorldDataSize(worldId, 0); - break; - case "set-setting": - if (String.IsNullOrEmpty(request.Key)) - { - logger.Warn("World {0} tried to delete data with no key provided", worldId); - this.lastError = "`key` is missing or null"; - return; - } - - if (String.IsNullOrEmpty(request.Value)) - { - logger.Warn("World {0} tried to set settings with no value provided", worldId); - this.lastError = "`value` is missing or null"; - return; - } - - SetWorldProperty(worldId, request.Key, request.Value); - break; - default: - logger.Warn("World {0} sent an invalid request type '{0}'", worldId, request.RequestType); - this.lastError = "Invalid request type"; - // invalid request type - return; - } - } - catch (Exception ex) - { - logger.Error(ex, "Failed to process world data request for world {0}", worldId); - logger.Error("Failed Request: {0}", json); - this.lastError = ex.Message; - return; - } - } - - /// - /// Sets a property for a given world in the world database. - /// - /// The ID of the world to set the property for. - /// The key of the property to set. - /// The value to set the property to. - public void SetWorldProperty(string worldId, string key, string value) - { - switch (key) - { - case "externalReads": - if (bool.TryParse(value, out bool result)) - { - worldDB.SetWorldAllowExternalRead(worldId, result); - } - else - { - logger.Warn("World {0} tried to set externalReads to an invalid value '{1}'", worldId, value); - this.lastError = "Invalid value for externalReads"; - return; - } - break; - } - } - - /// - /// Stores a data entry for a given world in the world database. - /// - /// The ID of the world to store the data entry for. - /// The key of the data entry to store. - /// The value of the data entry to store. - public void StoreWorldData(string worldId, string key, string value) - { - // Get/calculate the old and new data sizes for this key/the world - int oldTotalDataSize = worldDB.GetWorldDataSize(worldId); - int oldDataSize = worldDB.GetDataEntrySize(worldId, key); - int newDataSize = Encoding.UTF8.GetByteCount(value); - int newTotalDataSize = oldTotalDataSize + newDataSize - oldDataSize; - - // Make sure we don't exceed 10MB total size for a world - // This works, I tested it. Hopefully this prevents/limits any possible abuse. - if (newTotalDataSize > 1024 * 1024 * 10) - { - logger.Warn("World {0} exceeded 10MB total data size trying to store key {0}. {1}:{2} + {3} = {4}", key, worldId, oldTotalDataSize - oldDataSize, newDataSize, newTotalDataSize); - this.lastError = $"You have hit the 10MB total data cap. The previous data entry was *not* stored. Your request was {newDataSize} bytes, your current shared byte total is {oldTotalDataSize} and you went over the table limit by {newTotalDataSize - (1024 * 1024 * 10)} bytes."; - return; - } - - worldDB.AddDataEntry(worldId, key, value, newDataSize); - worldDB.UpdateWorldDataSize(worldId, newTotalDataSize); - logger.Info("World {0} stored data entry {1} with size {2} bytes", worldId, key, newDataSize); - logger.Debug("{0} : {1}", key, value); - } - - /// - /// Deletes a data entry for a given world from the world database. - /// - /// The ID of the world to delete the data entry from. - /// The key of the data entry to delete. - public void DeleteWorldData(string worldId, string key) - { - int oldTotalDataSize = worldDB.GetWorldDataSize(worldId); - int oldDataSize = worldDB.GetDataEntrySize(worldId, key); - int newTotalDataSize = oldTotalDataSize - oldDataSize; - - worldDB.DeleteDataEntry(worldId, key); - worldDB.UpdateWorldDataSize(worldId, newTotalDataSize); - logger.Info("World {0} deleted data entry {1} with size {2} bytes.", worldId, key, oldDataSize); - } - - public void Stop() - { - try - { - worldDB?.Close(); - listener?.Stop(); - listener?.Close(); - } - catch (ObjectDisposedException) - { - // ignore - } - } - } -} \ No newline at end of file diff --git a/Dotnet/PWI/WorldDataRequestResponse.cs b/Dotnet/PWI/WorldDataRequestResponse.cs deleted file mode 100644 index a8e27afa..00000000 --- a/Dotnet/PWI/WorldDataRequestResponse.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace VRCX -{ - public class WorldDataRequestResponse - { - /// - /// Gets or sets a value indicating whether the request was successful. - /// - [JsonProperty("ok")] - public bool OK { get; set; } - /// - /// Gets or sets the error message if the request was not successful. - /// - [JsonProperty("error")] - public string Error { get; set; } - /// - /// Gets or sets the data returned by the request. - /// - [JsonProperty("data")] - public string Data { get; set; } - /// - /// Gets or sets the response code. - /// - /// - [JsonProperty("statusCode")] - public int StatusCode { get; set; } - [JsonProperty("connectionKey")] - public string ConnectionKey { get; set; } - - public WorldDataRequestResponse(bool ok, string error, string data) - { - OK = ok; - Error = error; - Data = data; - } - } - - public class WorldDataRequest - { - [JsonProperty("requestType")] - public string RequestType; - [JsonProperty("connectionKey")] - public string ConnectionKey; - [JsonProperty("key")] - public string Key; - [JsonProperty("value")] - public string Value; - } -} diff --git a/Dotnet/PWI/WorldDatabase.cs b/Dotnet/PWI/WorldDatabase.cs deleted file mode 100644 index e6e746cd..00000000 --- a/Dotnet/PWI/WorldDatabase.cs +++ /dev/null @@ -1,322 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using SQLite; - -namespace VRCX -{ - [Table("data")] - public class WorldData - { - [PrimaryKey, AutoIncrement] - [Column("id")] - public int Id { get; set; } - [Column("world_id"), NotNull] - public string WorldId { get; set; } - [Column("key"), NotNull] - public string Key { get; set; } - [Column("value"), NotNull] - public string Value { get; set; } - [Column("value_size"), NotNull] - public int ValueSize { get; set; } - [Column("last_accessed")] - public DateTimeOffset LastAccessed { get; set; } - [Column("last_modified")] - public DateTimeOffset LastModified { get; set; } - } - - [Table("worlds")] - public class World - { - [PrimaryKey, AutoIncrement] - [Column("id")] - public int Id { get; set; } - [Column("world_id"), NotNull] - public string WorldId { get; set; } - [Column("connection_key"), NotNull] - public string ConnectionKey { get; set; } - [Column("total_data_size"), NotNull] - public int TotalDataSize { get; set; } - [Column("allow_external_read")] - public bool AllowExternalRead { get; set; } - } - - internal class WorldDatabase - { - private static SQLiteConnection sqlite; - private readonly static string dbInitQuery = @" -CREATE TABLE IF NOT EXISTS worlds ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - world_id TEXT NOT NULL UNIQUE, - connection_key TEXT NOT NULL, - total_data_size INTEGER DEFAULT 0, - allow_external_read INTEGER DEFAULT 0 -); -\ -CREATE TABLE IF NOT EXISTS data ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - world_id TEXT NOT NULL, - key TEXT NOT NULL, - value TEXT NOT NULL, - value_size INTEGER NOT NULL DEFAULT 0, - last_accessed INTEGER DEFAULT (strftime('%s', 'now')), - last_modified INTEGER DEFAULT (strftime('%s', 'now')), - FOREIGN KEY (world_id) REFERENCES worlds(world_id) ON DELETE CASCADE, - UNIQUE (world_id, key) -); -\ -CREATE TRIGGER IF NOT EXISTS data_update_trigger -AFTER UPDATE ON data -FOR EACH ROW -BEGIN - UPDATE data SET last_modified = (strftime('%s', 'now')) WHERE id = OLD.id; -END; -\ -CREATE TRIGGER IF NOT EXISTS data_insert_trigger -AFTER INSERT ON data -FOR EACH ROW -BEGIN - UPDATE data SET last_accessed = (strftime('%s', 'now')), last_modified = (strftime('%s', 'now')) WHERE id = NEW.id; -END;"; - public WorldDatabase(string databaseLocation) - { - var options = new SQLiteConnectionString(databaseLocation, true); - sqlite = new SQLiteConnection(options); - sqlite.Execute(dbInitQuery); - - // TODO: Split these init queries into their own functions so we can call/update them individually. - var queries = dbInitQuery.Split('\\'); - sqlite.BeginTransaction(); - foreach (var query in queries) - { - sqlite.Execute(query); - } - sqlite.Commit(); - } - - /// - /// Checks if a world with the specified ID exists in the database. - /// - /// The ID of the world to check for. - /// True if the world exists in the database, false otherwise. - public bool DoesWorldExist(string worldId) - { - var query = sqlite.Table().Where(w => w.WorldId == worldId).Select(w => w.WorldId); - - return query.Any(); - } - - /// - /// Gets the ID of the world with the specified connection key from the database. - /// - /// The connection key of the world to get the ID for. - /// The ID of the world with the specified connection key, or null if no such world exists in the database. - public string GetWorldByConnectionKey(string connectionKey) - { - var query = sqlite.Table().Where(w => w.ConnectionKey == connectionKey).Select(w => w.WorldId); - - return query.FirstOrDefault(); - } - - /// - /// Gets the connection key for a world from the database. - /// - /// The ID of the world to get the connection key for. - /// The connection key for the specified world, or null if the world does not exist in the database. - public string GetWorldConnectionKey(string worldId) - { - var query = sqlite.Table().Where(w => w.WorldId == worldId).Select(w => w.ConnectionKey); - - return query.FirstOrDefault(); - } - - /// - /// Sets the connection key for a world in the database. If the world already exists in the database, the connection key is updated. Otherwise, a new world is added to the database with the specified connection key. - /// - /// The ID of the world to set the connection key for. - /// The connection key to set for the world. - /// The connection key that was set. - public string SetWorldConnectionKey(string worldId, string connectionKey) - { - var query = sqlite.Table().Where(w => w.WorldId == worldId).Select(w => w.ConnectionKey); - - if (query.Any()) - { - sqlite.Execute("UPDATE worlds SET connection_key = ? WHERE world_id = ?", connectionKey, worldId); - } - else - { - sqlite.Insert(new World() { WorldId = worldId, ConnectionKey = connectionKey }); - } - - return connectionKey; - } - - /// - /// Sets the value of the allow_external_read field for the world with the specified ID in the database. - /// - /// The ID of the world to set the allow_external_read field for. - /// The value to set for the allow_external_read field. - public void SetWorldAllowExternalRead(string worldId, bool allowExternalRead) - { - sqlite.Execute("UPDATE worlds SET allow_external_read = ? WHERE world_id = ?", allowExternalRead, worldId); - } - - /// - /// Gets the value of the allow_external_read field for the world with the specified ID from the database. - /// - /// The ID of the world to get the allow_external_read field for. - /// The value of the allow_external_read field for the specified world. - public bool GetWorldAllowExternalRead(string worldId) - { - var query = sqlite.Table().Where(w => w.WorldId == worldId).Select(w => w.AllowExternalRead); - - return query.FirstOrDefault(); - } - - /// - /// Adds a new world to the database. - /// - /// The ID of the world to add. - /// The connection key of the world to add. - /// Thrown if a world with the specified ID already exists in the database. - public void AddWorld(string worldId, string connectionKey) - { - // * This will throw an error if the world already exists.. so don't do that - sqlite.Insert(new World() { WorldId = worldId, ConnectionKey = connectionKey }); - } - - /// - /// Gets the world with the specified ID from the database. - /// - /// The ID of the world to get. - /// The world with the specified ID, or null if no such world exists in the database. - public World GetWorld(string worldId) - { - var query = sqlite.Table().Where(w => w.WorldId == worldId); - return query.FirstOrDefault(); - } - - /// - /// Gets the total data size shared across all rows, in bytes, for the world with the specified ID from the database. - /// - /// The ID of the world to get the total data size for. - /// The total data size for the world, in bytes. - public int GetWorldDataSize(string worldId) - { - var query = sqlite.Table().Where(w => w.WorldId == worldId).Select(w => w.TotalDataSize); - - return query.FirstOrDefault(); - } - - /// - /// Updates the total data size, in bytes for the world with the specified ID in the database. - /// - /// The ID of the world to update the total data size for. - /// The new total data size for the world, in bytes. - public void UpdateWorldDataSize(string worldId, int size) - { - sqlite.Execute("UPDATE worlds SET total_data_size = ? WHERE world_id = ?", size, worldId); - } - - /// - /// Adds or updates a data entry in the database with the specified world ID, key, and value. - /// - /// The ID of the world to add the data entry for. - /// The key of the data entry to add or replace. - /// The value of the data entry to add or replace. - /// The size of the data entry to add or replace, in bytes. If null, the size is calculated from the value automatically. - public void AddDataEntry(string worldId, string key, string value, int? dataSize = null) - { - int byteSize = dataSize ?? Encoding.UTF8.GetByteCount(value); - - // check if entry already exists; - // INSERT OR REPLACE(InsertOrReplace method) deletes the old row and creates a new one, incrementing the id, which I don't want - var query = sqlite.Table().Where(w => w.WorldId == worldId && w.Key == key); - if (query.Any()) - { - sqlite.Execute("UPDATE data SET value = ?, value_size = ? WHERE world_id = ? AND key = ?", value, byteSize, worldId, key); - } - else - { - sqlite.Insert(new WorldData() { WorldId = worldId, Key = key, Value = value, ValueSize = byteSize }); - } - } - - /// - /// Gets the data entry with the specified world ID and key from the database. - /// - /// The ID of the world to get the data entry for. - /// The key of the data entry to get. - /// The data entry with the specified world ID and key, or null if no such data entry exists in the database. - public WorldData GetDataEntry(string worldId, string key) - { - var query = sqlite.Table().Where(w => w.WorldId == worldId && w.Key == key); - - return query.FirstOrDefault(); - } - - /// - /// Gets the data entries with the specified world ID and keys from the database. - /// - /// The ID of the world to get the data entries for. - /// The keys of the data entries to get. - /// An enumerable collection of the data entries with the specified world ID and keys. - public IEnumerable GetDataEntries(string worldId, string[] keys) - { - var query = sqlite.Table().Where(w => w.WorldId == worldId && keys.Contains(w.Key)); - - return query.ToList(); - } - - /// - /// Gets all data entries for the world with the specified ID from the database. - /// - /// The ID of the world to get the data entries for. - /// An enumerable collection of all data entries for the world with the specified ID. - public IEnumerable GetAllDataEntries(string worldId) - { - var query = sqlite.Table().Where(w => w.WorldId == worldId).Take(10000); - return query.ToList(); - } - - /// - /// Gets the size of the data entry, in bytes, with the specified world ID and key from the database. - /// - /// The ID of the world to get the data entry size for. - /// The key of the data entry to get the size for. - /// The size of the data entry with the specified world ID and key, or 0 if no such data entry exists in the database. - public int GetDataEntrySize(string worldId, string key) - { - var query = sqlite.Table().Where(w => w.WorldId == worldId && w.Key == key).Select(w => w.ValueSize); - - return query.FirstOrDefault(); - } - - /// - /// Deletes the data entry with the specified world ID and key from the database. - /// - /// The ID of the world to delete the data entry from. - /// The key of the data entry to delete. - public void DeleteDataEntry(string worldId, string key) - { - sqlite.Execute("DELETE FROM data WHERE world_id = ? AND key = ?", worldId, key); - } - - /// - /// Deletes all data entries for the world with the specified ID from the database. - /// - /// The ID of the world to delete all data entries for. - public void DeleteAllDataEntriesForWorld(string worldId) - { - sqlite.Execute("DELETE FROM data WHERE world_id = ?", worldId); - } - - public void Close() - { - sqlite.Close(); - } - } -} diff --git a/Dotnet/Program.cs b/Dotnet/Program.cs index 340783cc..b5d41282 100644 --- a/Dotnet/Program.cs +++ b/Dotnet/Program.cs @@ -8,6 +8,7 @@ using NLog; using NLog.Targets; using System; using System.Data.SQLite; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text.Json; using System.Threading; @@ -99,14 +100,12 @@ namespace VRCX // Layout with padding between the level/logger and message so that the message always starts at the same column Layout = "${longdate} [${level:uppercase=true:padding=-5}] ${logger:padding=-20} - ${message} ${exception:format=tostring}", - ArchiveFileName = Path.Join(AppDataDirectory, "logs", "VRCX.{#}.log"), - ArchiveNumbering = ArchiveNumberingMode.DateAndSequence, + ArchiveSuffixFormat = "{0:000}", ArchiveEvery = FileArchivePeriod.Day, MaxArchiveFiles = 4, MaxArchiveDays = 7, ArchiveAboveSize = 10000000, ArchiveOldFileOnStartup = true, - ConcurrentWrites = true, KeepFileOpen = true, AutoFlush = true, Encoding = System.Text.Encoding.UTF8 @@ -118,12 +117,13 @@ namespace VRCX Layout = "${longdate} [${level:uppercase=true:padding=-5}] ${logger:padding=-20} - ${message} ${exception:format=tostring}", DetectConsoleAvailable = true }; - builder.ForLogger("VRCX").FilterMinLevel(LogLevel.Info).WriteTo(consoleTarget); + builder.ForLogger().FilterMinLevel(LogLevel.Debug).WriteTo(consoleTarget); }); } #if !LINUX [STAThread] + [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] private static void Main() { if (Wine.GetIfWine()) @@ -150,7 +150,7 @@ namespace VRCX { case DialogResult.Yes: logger.Fatal("Handled Exception, user selected auto install of vc_redist."); - Update.DownloadInstallRedist(); + Update.DownloadInstallRedist().GetAwaiter().GetResult(); MessageBox.Show( "vc_redist has finished installing, if the issue persists upon next restart, please reinstall VRCX From GitHub,\nVRCX Will now restart.", "vc_redist installation complete", MessageBoxButtons.OK); @@ -210,6 +210,7 @@ namespace VRCX } } + [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] private static void Run() { var args = Environment.GetCommandLineArgs(); @@ -236,7 +237,6 @@ namespace VRCX AppApiVr.Instance.Init(); ProcessMonitor.Instance.Init(); Discord.Instance.Init(); - WorldDBManager.Instance.Init(); WebApi.Instance.Init(); LogWatcher.Instance.Init(); AutoAppLaunchManager.Instance.Init(); @@ -258,7 +258,6 @@ namespace VRCX AutoAppLaunchManager.Instance.Exit(); LogWatcher.Instance.Exit(); WebApi.Instance.Exit(); - WorldDBManager.Instance.Stop(); Discord.Instance.Exit(); SystemMonitor.Instance.Exit(); diff --git a/Dotnet/SharedVariable.cs b/Dotnet/SharedVariable.cs deleted file mode 100644 index 8c9acedb..00000000 --- a/Dotnet/SharedVariable.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright(c) 2019-2025 pypy, Natsumi and individual contributors. -// All rights reserved. -// -// This work is licensed under the terms of the MIT license. -// For a copy, see . - -using System.Collections.Generic; -using System.Threading; - -namespace VRCX -{ - public class SharedVariable - { - public static readonly SharedVariable Instance; - private readonly ReaderWriterLockSlim m_MapLock; - private readonly Dictionary m_Map; - - static SharedVariable() - { - Instance = new SharedVariable(); - } - - public SharedVariable() - { - m_MapLock = new ReaderWriterLockSlim(); - m_Map = new Dictionary(); - } - - public void Clear() - { - m_MapLock.EnterWriteLock(); - try - { - m_Map.Clear(); - } - finally - { - m_MapLock.ExitWriteLock(); - } - } - - public string Get(string key) - { - m_MapLock.EnterReadLock(); - try - { - if (m_Map.TryGetValue(key, out string value) == true) - { - return value; - } - } - finally - { - m_MapLock.ExitReadLock(); - } - - return null; - } - - public void Set(string key, string value) - { - m_MapLock.EnterWriteLock(); - try - { - m_Map[key] = value; - } - finally - { - m_MapLock.ExitWriteLock(); - } - } - - public bool Remove(string key) - { - m_MapLock.EnterWriteLock(); - try - { - return m_Map.Remove(key); - } - finally - { - m_MapLock.ExitWriteLock(); - } - } - } -} diff --git a/Dotnet/VRCX-Cef.csproj b/Dotnet/VRCX-Cef.csproj index e931954e..de5a0996 100644 --- a/Dotnet/VRCX-Cef.csproj +++ b/Dotnet/VRCX-Cef.csproj @@ -91,12 +91,12 @@ - - + + - + @@ -104,10 +104,10 @@ - - + + - + diff --git a/Dotnet/VRCX-Electron.csproj b/Dotnet/VRCX-Electron.csproj index 17bbb8bd..59f5bf78 100644 --- a/Dotnet/VRCX-Electron.csproj +++ b/Dotnet/VRCX-Electron.csproj @@ -93,12 +93,12 @@ - - + + - + @@ -106,10 +106,10 @@ - - + + - + @@ -121,8 +121,6 @@ - - diff --git a/README.es.md b/README.es.md index 636a1e7f..f17da05e 100644 --- a/README.es.md +++ b/README.es.md @@ -33,10 +33,6 @@ Versión beta/nocturna disponible [aquí](https://vrcx.app/github/nightly) o en - :electric_plug: Inicia automáticamente aplicaciones cuando inicias VRChat - Puedes configurar VRCX para iniciar otras aplicaciones cuando inicias VRChat. - Por ejemplo, podrías hacer que VRCX inicie una aplicación OSC o una aplicación de cambio de voz cuando se abra VRChat. -- :floppy_disk: Persistencia de mundos - - Para los mundos que soportan la función, VRCX puede guardar configuraciones de mundos, estados guardados, inventarios y otros datos. - - **Nota**: Para usar esta función, debes tener "Permitir URLs no confiables" habilitado en la configuración de VRChat. - - Para desarrolladores: [Página Wiki - Persistencia de Mundos (PWI)]() - :mag: Busca avatares, usuarios, mundos y grupos - :earth_americas: Crea una lista de favoritos de mundos local y sin restricciones - :camera: Almacena datos de mundos en las fotos que tomas en el juego, para que puedas recordar ese mundo donde tomaste esas fotos geniales hace como... 6 meses. diff --git a/README.fr.md b/README.fr.md index aa220c5f..eb1c1b8d 100644 --- a/README.fr.md +++ b/README.fr.md @@ -31,10 +31,6 @@ Téléchargez et exécutez le dernier programme d'installation (`VRCX_Setup.exe` - :electric_plug: Lancement automatique d'applications lorsque vous démarrez VRChat - Vous pouvez configurer VRCX pour lancer d'autres applications lorsque vous démarrez VRChat. - Par exemple, vous pourriez avoir VRCX qui lance une application OSC ou une application de modification de voix lorsque VRChat s'ouvre. -- :floppy_disk: Persistance de Monde - - Pour les mondes qui prennent en charge cette fonctionnalité, VRCX peut sauvegarder les paramètres de monde, les états sauvegardés, les inventaires et d'autres données ! - - **Note** : Pour utiliser cette fonctionnalité, vous devez avoir activé "Allow Untrusted URLs" dans vos paramètres VRChat. - - Pour les Développeurs : [Page Wiki - World Persistence (PWI)]() - :mag: Recherche d'avatars, d'utilisateurs, de mondes et de groupes - :earth_americas: Créez une liste de favoris de mondes locale et sans restrictions - :camera: Stockez les données du monde dans les images que vous prenez en jeu, afin de vous souvenir de ce monde où vous avez pris ces superbes photos il y a... 6 mois ! diff --git a/README.it.md b/README.it.md index efe12601..e9f750d0 100644 --- a/README.it.md +++ b/README.it.md @@ -31,10 +31,6 @@ Scarica e installa l'ultimo installer (`VRCX_Setup.exe`) da [qui](https://github - :electric_plug: Avvio automatico delle applicazioni all'avvio di VRChat - È possibile configurare VRCX per avviare altre applicazioni quando si avvia VRChat. - Ad esempio, si può fare in modo che VRCX lanci un'applicazione OSC o un cambiavoce all'apertura di VRChat. -- :floppy_disk: Persistenza del mondo - - Per i mondi che supportano questa funzione, VRCX può salvare le impostazioni del mondo, gli stati, gli inventari e altri dati! - - **Nota**: Per utilizzare questa funzione, è necessario che nelle impostazioni di VRChat sia abilitato "Consenti URL non attendibili". - - Per gli sviluppatori: [Pagina Wiki - World Persistence (PWI)]() - :mag: Ricerca di avatar, utenti, mondi e gruppi - :earth_americas: Costruire un elenco di preferiti locali e non limitati del mondo - :camera: Memorizza i dati del mondo nelle foto scattate nel gioco, in modo da poter ricordare quel mondo in cui hai scattato quelle belle foto come... 6 mesi fa! diff --git a/README.jp.md b/README.jp.md index 1633bb87..dd0a59e0 100644 --- a/README.jp.md +++ b/README.jp.md @@ -31,10 +31,6 @@ VRCX は VRChat クライアント (デスクトップ & VR) や Web サイト - :electric_plug: VRChat 起動時に一緒にアプリを起動 - VRChat の起動時に他のアプリを同時起動できるよう設定できます。 - 例えば、VRChat を起動したら同時に OSC アプリやボイスチェンジャーを起動するようにできます。 -- :floppy_disk: ワールドの永続化 - - ワールドが対応している場合、設定やセーブデータ、インベントリなどのデータを保存することができます。 - - **注意**: この機能を使うには、VRChat の設定で「信頼されていない URL を許可」を有効化しておく必要があります。 - - 開発者向け: [Wiki Page - World Persistence (PWI)]() - :mag: アバター、ユーザー、ワールド、グループの検索 - :earth_americas: 無制限!ローカル保存のワールドお気に入りリスト - :camera: ゲーム内で撮った写真にワールドデータを保存することで、半年前に撮影した綺麗なワールドをいつでも振り返ることができます。 diff --git a/README.md b/README.md index cb9aa077..96be9973 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ [![GitHub release](https://img.shields.io/github/release/vrcx-team/VRCX.svg)](https://github.com/vrcx-team/VRCX/releases/latest) [![Downloads](https://img.shields.io/github/downloads/vrcx-team/VRCX/total?color=6451f1)](https://github.com/vrcx-team/VRCX/releases/latest) [![GitHub Workflow Status](https://github.com/vrcx-team/VRCX/actions/workflows/github_actions.yml/badge.svg)](https://github.com/vrcx-team/VRCX/actions/workflows/github_actions.yml) -[![Crowdin](https://badges.crowdin.net/vrcx/localized.svg)](https://crowdin.com/project/vrcx) [![VRCX Discord Invite](https://img.shields.io/discord/854071236363550763?color=%237289DA&logo=discord&logoColor=white&label=discord)](https://vrcx.app/discord) | **English** | [Français](./README.fr.md) | [日本語](./README.jp.md) | [简体中文](./README.zh_CN.md) | [Italiano](./README.it.md) | [Русский](./README.ru_RU.md) | [Español](./README.es.md) | [Polski](./README.pl.md) @@ -34,10 +33,6 @@ Beta/nightly build available [here](https://vrcx.app/github/nightly) or in-app ` - :electric_plug: Automatically launch apps when you start VRChat - You can configure VRCX to launch other apps when you start VRChat. - For example, you could have VRCX launch an OSC app or a voice changer app when VRChat opens up. -- :floppy_disk: World Persistence - - For worlds that support the feature, VRCX can save world settings, save states, inventories, and other data! - - **Note**: To use this feature, you must have "Allow Untrusted URLs" enabled in your VRChat settings. - - For Developers: [Wiki Page - World Persistence (PWI)]() - :mag: Search for avatars, users, worlds, and groups - :earth_americas: Build a local, unrestricted world favorites list - :camera: Store world data in the pictures you take in-game, so you can remember that one world you took those cool pictures in like... 6 months ago! @@ -47,7 +42,7 @@ Beta/nightly build available [here](https://vrcx.app/github/nightly) or in-app ` - :tv: See the links to videos and that are playing in the world you're in, as well as various other logged data. - :bar_chart: Improved Discord Rich Presence - You can optionally display more information about your current instance in Discord. - - World integration for popular worlds like PyPyDance, LSMedia, Movies&Chill and VRDancing. + - World integration for popular worlds like Popcorn Palace, PyPyDance, VRDancing and LSMedia. - This includes the world thumbnail, name, instance ID, and player count, depending on your settings and whether the lobby is private. You can also add a join button for public lobbies! - :crystal_ball: VR Overlay with configurable live feed of all supported events/notifications - :outbox_tray: Upload avatar/world images without Unity diff --git a/README.pl.md b/README.pl.md index 507799bf..cee6bacc 100644 --- a/README.pl.md +++ b/README.pl.md @@ -31,10 +31,6 @@ Pobierz i uruchom najnowszy instalator (`VRCX_Setup.exe`) [stąd](https://github - :electric_plug: Automatycznie uruchamiaj aplikacje podczas startu VRChat - Ustaw, aby VRCX uruchamiał inne aplikacje, gdy włączysz VRChat. - Na przykład, możesz ustawić, aby VRCX uruchamiał aplikację OSC lub modulacji głosu, gdy włączysz VRChat. -- :floppy_disk: Persystencja światów - - VRCX może zapisywać ustawienia, stany, ekwipunek czy inne dane światów, jeżeli wspierają one tę funkcję. - - **Notatka**: Aby używać tej funkcji, musisz zezwolić na niezaufane linki URL w ustawieniach VRChatu. - - Dla programistów: [Strona wiki o persystencji światów]() - :mag: Wyszukuj awatary, użytkwoników, światy i grupy - :earth_americas: Twórz lokalną i nieograniczoną listę ulubionych światów - :camera: Przechowuj dane światów w zdjęciach robionych w grze, aby pamiętać o światach odwiedzanych dawno temu! diff --git a/README.ru_RU.md b/README.ru_RU.md index 30df7abd..e5e730d6 100644 --- a/README.ru_RU.md +++ b/README.ru_RU.md @@ -33,10 +33,6 @@ VRCX является ассистентом/компаньоном прилож - :electric_plug: Автоматически запускает приложения при запуске VRChat - Вы можете настроить VRCX на запуск других приложений при запуске VRChat. - Например, при открытии VRChat вы можете запустить приложение OSC или программу для изменения голоса. -- :floppy_disk: Сохранение мира - - В мирах, поддерживающих эту функцию, VRCX может сохранять настройки мира, сохранять состояния, инвентарь и другие данные! - - **Примечание**: Для использования этой функции в настройках VRChat должна быть включена опция "Разрешить недоверенные URL'ы" ("Allow Untrusted URLs"). - - Для разработчиков: [Вики страница - Сохранение мира (PWI)]() - :mag: Поиск аватаров, пользователей, миров и групп - :earth_americas: Создает локальный, неограниченный список избранных миров - :camera: Храните данные о мире в фотографиях, которые вы делаете в игре, чтобы вы могли вспомнить тот мир, в котором вы сделали те классные фотографии, например... 6 месяцев назад! diff --git a/README.zh_CN.md b/README.zh_CN.md index ef13f18b..6759a58e 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -33,10 +33,6 @@ VRCX 是一款用于 VRChat 的外部辅助小工具,可以比 VRChat 游戏 - :electric_plug: 当你启动 VRChat 时自动启动其他程序 - 你可以配置 VRCX,让其在启动 VRChat 时自动启动你指定的程序。 - 例如,你可以在启动时让 VRCX 打开一个 OSC 应用或变声器。 -- :floppy_disk: 世界数据持久化保存 (World Persistence) - - 对于支持此功能的世界,VRCX 将能够保存世界设置、存档、各种清单以及其他可以保存的数据! - - **注意**:要使用此功能,必须在 VRChat 设置中启用 “Allow Untrusted URLs”。 - - 给世界开发者的指南: [Wiki Page - World Persistence (PWI)]() - :mag: 以更加方便的形式搜索模型、房间、世界以及群组。 - :earth_americas: 创建本地的、没有任何限制的世界收藏夹 - :camera: 将世界数据存储在你在游戏内拍摄的照片中,这样即使几个月后也能知道当时是在什么世界拍的照片 diff --git a/build-scripts/build-dotnet.cmd b/build-scripts/dotnet/build-dotnet.cmd similarity index 72% rename from build-scripts/build-dotnet.cmd rename to build-scripts/dotnet/build-dotnet.cmd index 971c11aa..54debb8d 100644 --- a/build-scripts/build-dotnet.cmd +++ b/build-scripts/dotnet/build-dotnet.cmd @@ -1,5 +1,4 @@ @echo off -cd .. +cd ../../ dotnet build Dotnet\VRCX-Cef.csproj -p:Configuration=Release -p:Platform=x64 -p:RestorePackagesConfig=true -t:"Restore;Clean;Build" -m --self-contained -mklink /J "%~dp0\..\build\Cef\html" "%~dp0\..\build\html" pause diff --git a/build-scripts/make-junction.cmd b/build-scripts/make-junction.cmd index 2c617cff..6e248075 100644 --- a/build-scripts/make-junction.cmd +++ b/build-scripts/make-junction.cmd @@ -1,6 +1,12 @@ @echo off setlocal enabledelayedexpansion +if not exist "%~dp0\..\build\Cef" ( + mkdir "%~dp0\..\build\Cef" +) +if not exist "%~dp0\..\build\html" ( + mkdir "%~dp0\..\build\html" +) if not exist "%~dp0\..\build\Cef\html" ( mklink /J "%~dp0\..\build\Cef\html" "%~dp0\..\build\html" ) \ No newline at end of file diff --git a/build-scripts/node/build-node-debug.cmd b/build-scripts/node/build-node-debug.cmd new file mode 100644 index 00000000..7511eaa5 --- /dev/null +++ b/build-scripts/node/build-node-debug.cmd @@ -0,0 +1,3 @@ +cd ../../ +call npm run dev +pause diff --git a/build-scripts/build-node.js.cmd b/build-scripts/node/build-node-release.cmd similarity index 55% rename from build-scripts/build-node.js.cmd rename to build-scripts/node/build-node-release.cmd index c5d8cbbb..42913114 100644 --- a/build-scripts/build-node.js.cmd +++ b/build-scripts/node/build-node-release.cmd @@ -1,4 +1,3 @@ -cd ../ -call npm ci +cd ../../ call npm run prod pause diff --git a/build-scripts/node/restore-node-dependencies.cmd b/build-scripts/node/restore-node-dependencies.cmd new file mode 100644 index 00000000..d8ba3229 --- /dev/null +++ b/build-scripts/node/restore-node-dependencies.cmd @@ -0,0 +1,3 @@ +cd ../../ +call npm ci +pause diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..f534b1be --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,60 @@ +import js from '@eslint/js'; +import pluginVue from 'eslint-plugin-vue'; +import { defineConfig } from 'eslint/config'; +import globals from 'globals'; + +export default defineConfig([ + { + files: ['**/*.{js,mjs,cjs,vue}'], + plugins: { js }, + extends: ['js/recommended'] + }, + { + files: ['**/*.{js,mjs,cjs,vue}'], + languageOptions: { + globals: { + ...globals.browser, + CefSharp: 'readonly', + VRCX: 'readonly', + VRCXStorage: 'readonly', + SQLite: 'readonly', + LogWatcher: 'readonly', + Discord: 'readonly', + AppApi: 'readonly', + AppApiVr: 'readonly', + WebApi: 'readonly', + AssetBundleManager: 'readonly', + WINDOWS: 'readonly', + LINUX: 'readonly', + webApiService: 'readonly', + process: 'readonly' + } + } + }, + { + files: [ + '**/webpack.*.js', + 'src-electron/*.js', + 'src/localization/*.js' + ], + languageOptions: { + sourceType: 'commonjs', + globals: { + ...globals.node + } + } + }, + pluginVue.configs['flat/vue2-essential'], + { + rules: { + 'no-unused-vars': 'warn', + 'no-case-declarations': 'off', + 'no-control-regex': 'warn', + + 'vue/no-mutating-props': 'warn', + 'vue/multi-word-component-names': 'off', + 'vue/no-v-text-v-html-on-component': 'off', + 'vue/no-use-v-if-with-v-for': 'warn' + } + } +]); diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 00000000..d3164e9c --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "ESNext", + "target": "ESNext", + "allowJs": true, + "checkJs": true, + "jsx": "preserve", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "skipLibCheck": true, + "moduleResolution": "bundler", + "forceConsistentCasingInFileNames": true, + "lib": ["esnext", "dom", "dom.iterable"] + }, + "include": ["src/**/*", "src-electron/**/*"], + "exclude": ["node_modules", "build"] +} diff --git a/package-lock.json b/package-lock.json index 54bd80ba..e12df1a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,264 +8,86 @@ "license": "MIT", "dependencies": { "hazardous": "^0.3.0", - "node-api-dotnet": "^0.9.11" + "node-api-dotnet": "^0.9.12" }, "devDependencies": { - "@babel/eslint-parser": "^7.27.5", "@electron/rebuild": "^4.0.1", - "@fontsource/noto-sans-jp": "^5.2.5", - "@fontsource/noto-sans-kr": "^5.2.5", + "@eslint/js": "^9.30.0", + "@fontsource/noto-sans-jp": "^5.2.6", + "@fontsource/noto-sans-kr": "^5.2.6", "@fontsource/noto-sans-sc": "^5.2.6", "@fontsource/noto-sans-tc": "^5.2.6", "@infolektuell/noto-color-emoji": "^0.2.0", "@prettier/plugin-pug": "^3.4.0", + "@types/node": "^24.0.12", "animate.css": "^4.1.1", "copy-webpack-plugin": "^13.0.0", "cross-env": "^7.0.3", "css-loader": "^7.1.2", "dayjs": "^1.11.13", - "default-passive-events": "^4.0.0", "echarts": "^5.6.0", - "electron": "^36.4.0", + "electron": "^37.1.0", "electron-builder": "^26.0.12", "element-ui": "^2.15.14", "esbuild-loader": "^4.3.0", - "eslint": "^9.28.0", + "eslint": "^9.30.0", "eslint-config-prettier": "^10.1.5", - "eslint-plugin-vue": "^9.32.0", + "eslint-plugin-vue": "^9.33.0", + "globals": "^16.2.0", "html-webpack-plugin": "^5.6.3", "mini-css-extract-plugin": "^2.9.2", - "normalize.css": "^8.0.1", "noty": "^3.2.0-beta-deprecated", - "prettier": "^3.5.3", + "pinia": "^2.3.1", + "prettier": "^3.6.2", "pug": "^3.0.3", "pug-plain-loader": "^1.1.0", "raw-loader": "^4.0.2", - "sass": "^1.89.1", + "sass": "^1.89.2", "sass-loader": "^16.0.5", "vue": "^2.7.16", "vue-data-tables": "^3.4.5", "vue-demi": "^0.14.10", "vue-i18n": "^8.28.2", "vue-i18n-bridge": "^9.14.1", - "vue-lazyload": "^1.3.4", + "vue-lazyload": "^1.3.5", "vue-loader": "^15.11.1", "vue-markdown": "^2.2.4", "vue-marquee-text-component": "^1.2.0", "webpack": "^5.99.9", "webpack-cli": "^6.0.1", - "worker-timers": "^8.0.21", + "webpack-dev-server": "^5.2.2", + "worker-timers": "^8.0.22", "yargs": "^18.0.0" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", - "dev": true, - "peer": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/eslint-parser": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.27.5.tgz", - "integrity": "sha512-HLkYQfRICudzcOtjGwkPvGc5nF1b4ljLZh1IRDj50lRZ718NAKVgQpIAUX8bfg6u/yuSKY3L7E0YzIV+OxrB8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.11.0", - "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz", - "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/parser": "^7.26.9", - "@babel/types": "^7.26.9", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", - "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/compat-data": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", - "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.0" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz", - "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.26.9" + "@babel/types": "^7.28.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -275,60 +97,24 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", - "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", + "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/template": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", - "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.26.9", - "@babel/types": "^7.26.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz", - "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.9", - "@babel/parser": "^7.26.9", - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.9", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/types": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz", - "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.0.tgz", + "integrity": "sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -380,36 +166,17 @@ "node": ">=10.12.0" } }, - "node_modules/@electron/asar/node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/@electron/asar/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/@electron/asar/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "brace-expansion": "^1.1.7" }, "engines": { "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@electron/fuses": { @@ -443,6 +210,29 @@ "node": ">=10" } }, + "node_modules/@electron/fuses/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/fuses/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/@electron/get": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", @@ -465,45 +255,20 @@ "global-agent": "^3.0.0" } }, - "node_modules/@electron/get/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "node_modules/@electron/get/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/@electron/get/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/get/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, "node_modules/@electron/node-gyp": { "version": "10.2.0-electron.1", "resolved": "git+ssh://git@github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2", - "integrity": "sha512-CrYo6TntjpoMO1SHjl5Pa/JoUsECNqNdB7Kx49WLQpWzPw53eEITJ2Hs9fh/ryUYDn4pxZz11StaBYBrLFJdqg==", + "integrity": "sha512-4MSBTT8y07YUDqf69/vSh80Hh791epYqGtWHO3zSKhYFwQg+gx9wi1PqbqP6YqC4WMsNxZ5l9oDmnWdK5pfCKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -525,19 +290,421 @@ "node": ">=12.13.0" } }, - "node_modules/@electron/node-gyp/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "node_modules/@electron/node-gyp/node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", "dev": true, "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@electron/node-gyp/node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/@electron/node-gyp/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@electron/node-gyp/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@electron/node-gyp/node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@electron/node-gyp/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@electron/node-gyp/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@electron/node-gyp/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@electron/node-gyp/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@electron/node-gyp/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/node-gyp/node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@electron/node-gyp/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { "node": ">=10" } }, + "node_modules/@electron/node-gyp/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@electron/node-gyp/node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@electron/node-gyp/node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/@electron/node-gyp/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@electron/node-gyp/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@electron/node-gyp/node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@electron/node-gyp/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@electron/node-gyp/node_modules/proc-log": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@electron/node-gyp/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@electron/node-gyp/node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/node-gyp/node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@electron/node-gyp/node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/node-gyp/node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@electron/node-gyp/node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@electron/node-gyp/node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@electron/node-gyp/node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/@electron/notarize": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz", @@ -569,6 +736,29 @@ "node": ">=10" } }, + "node_modules/@electron/notarize/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/notarize/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/@electron/osx-sign": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.1.tgz", @@ -591,6 +781,21 @@ "node": ">=12.0.0" } }, + "node_modules/@electron/osx-sign/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", @@ -604,6 +809,29 @@ "url": "https://github.com/sponsors/gjtorikian/" } }, + "node_modules/@electron/osx-sign/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/osx-sign/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/@electron/rebuild": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-4.0.1.tgz", @@ -648,42 +876,6 @@ "node": ">=12" } }, - "node_modules/@electron/rebuild/node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/@electron/rebuild/node_modules/node-abi": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.8.0.tgz", - "integrity": "sha512-+P1Mf1XNURT+wN9UK8cjtHSwmmG02iAsX0JaYDDdXgMUe5eybde3AKpGGxOrkDmPkuonYJ6WjIRrNVQe0kjmFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.6.3" - }, - "engines": { - "node": ">=22.12.0" - } - }, - "node_modules/@electron/rebuild/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@electron/rebuild/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -751,9 +943,9 @@ } }, "node_modules/@electron/universal/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -775,6 +967,19 @@ "node": ">=14.14" } }, + "node_modules/@electron/universal/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/@electron/universal/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -791,10 +996,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@electron/universal/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/@electron/windows-sign": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.1.tgz", - "integrity": "sha512-YfASnrhJ+ve6Q43ZiDwmpBgYgi2u0bYjeAVi2tDfN7YWAKO8X9EEOuPGtqbJpPLM6TfAHimghICjWe2eaJ8BAg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz", + "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", "dev": true, "license": "BSD-2-Clause", "optional": true, @@ -830,10 +1045,37 @@ "node": ">=14.14" } }, + "node_modules/@electron/windows-sign/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/windows-sign/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", - "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz", + "integrity": "sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==", "cpu": [ "ppc64" ], @@ -848,9 +1090,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", - "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.6.tgz", + "integrity": "sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==", "cpu": [ "arm" ], @@ -865,9 +1107,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", - "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.6.tgz", + "integrity": "sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==", "cpu": [ "arm64" ], @@ -882,9 +1124,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", - "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.6.tgz", + "integrity": "sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==", "cpu": [ "x64" ], @@ -899,9 +1141,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", - "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.6.tgz", + "integrity": "sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==", "cpu": [ "arm64" ], @@ -916,9 +1158,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", - "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.6.tgz", + "integrity": "sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==", "cpu": [ "x64" ], @@ -933,9 +1175,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", - "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.6.tgz", + "integrity": "sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==", "cpu": [ "arm64" ], @@ -950,9 +1192,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", - "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.6.tgz", + "integrity": "sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==", "cpu": [ "x64" ], @@ -967,9 +1209,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", - "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.6.tgz", + "integrity": "sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==", "cpu": [ "arm" ], @@ -984,9 +1226,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", - "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.6.tgz", + "integrity": "sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==", "cpu": [ "arm64" ], @@ -1001,9 +1243,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", - "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.6.tgz", + "integrity": "sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==", "cpu": [ "ia32" ], @@ -1018,9 +1260,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", - "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.6.tgz", + "integrity": "sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==", "cpu": [ "loong64" ], @@ -1035,9 +1277,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", - "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.6.tgz", + "integrity": "sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==", "cpu": [ "mips64el" ], @@ -1052,9 +1294,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", - "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.6.tgz", + "integrity": "sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==", "cpu": [ "ppc64" ], @@ -1069,9 +1311,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", - "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.6.tgz", + "integrity": "sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==", "cpu": [ "riscv64" ], @@ -1086,9 +1328,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", - "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.6.tgz", + "integrity": "sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==", "cpu": [ "s390x" ], @@ -1103,9 +1345,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", - "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.6.tgz", + "integrity": "sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==", "cpu": [ "x64" ], @@ -1120,9 +1362,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", - "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.6.tgz", + "integrity": "sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==", "cpu": [ "arm64" ], @@ -1137,9 +1379,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", - "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.6.tgz", + "integrity": "sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==", "cpu": [ "x64" ], @@ -1154,9 +1396,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", - "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.6.tgz", + "integrity": "sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==", "cpu": [ "arm64" ], @@ -1171,9 +1413,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", - "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.6.tgz", + "integrity": "sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==", "cpu": [ "x64" ], @@ -1187,10 +1429,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.6.tgz", + "integrity": "sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", - "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.6.tgz", + "integrity": "sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==", "cpu": [ "x64" ], @@ -1205,9 +1464,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", - "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.6.tgz", + "integrity": "sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==", "cpu": [ "arm64" ], @@ -1222,9 +1481,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", - "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.6.tgz", + "integrity": "sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==", "cpu": [ "ia32" ], @@ -1239,9 +1498,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", - "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz", + "integrity": "sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==", "cpu": [ "x64" ], @@ -1256,10 +1515,11 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" }, @@ -1278,6 +1538,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -1290,14 +1551,15 @@ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/config-array": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", - "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1309,10 +1571,23 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/config-helpers": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", - "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1320,9 +1595,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", - "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1369,10 +1644,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { - "version": "9.28.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz", - "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==", + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz", + "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==", "dev": true, "license": "MIT", "engines": { @@ -1393,13 +1681,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", - "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz", + "integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.14.0", + "@eslint/core": "^0.15.1", "levn": "^0.4.1" }, "engines": { @@ -1407,9 +1695,9 @@ } }, "node_modules/@fontsource/noto-sans-jp": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@fontsource/noto-sans-jp/-/noto-sans-jp-5.2.5.tgz", - "integrity": "sha512-ISoJUQlsuSo4y56P+eJD+g022BRAF1BC2uCyEFGRsob0g8VvQAoWNMlWh+P0VQw68QzZHHj41zRzeRFpzAdA7w==", + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@fontsource/noto-sans-jp/-/noto-sans-jp-5.2.6.tgz", + "integrity": "sha512-BvUHYZKL87yWGRNFqInxDciU/Czp6klOEcB9l/6CnjMN77F5jc21r/A4XkMx46eY8FzVvfjCYTYUB4zExlX2Ww==", "dev": true, "license": "OFL-1.1", "funding": { @@ -1417,9 +1705,9 @@ } }, "node_modules/@fontsource/noto-sans-kr": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@fontsource/noto-sans-kr/-/noto-sans-kr-5.2.5.tgz", - "integrity": "sha512-9swPyua410J00z+GhemPKK/StWdiW07dchS9JcskesdQrhnPBLD6zVQtQsrj+ZPXTFBftbcrMlWFsWhmFn6S9w==", + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@fontsource/noto-sans-kr/-/noto-sans-kr-5.2.6.tgz", + "integrity": "sha512-8yVWUzOT+El3PAqY8ZKvNatgzL7EgrvLoNp0GjYSLkgDKvvX+xaIZ34W8gfATjeXKmolj9lQN4TqADfPlbmUsg==", "dev": true, "license": "OFL-1.1", "funding": { @@ -1458,6 +1746,7 @@ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18.0" } @@ -1467,6 +1756,7 @@ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" @@ -1480,6 +1770,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -1493,6 +1784,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -1502,9 +1794,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1519,7 +1811,8 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/@infolektuell/noto-color-emoji/-/noto-color-emoji-0.2.0.tgz", "integrity": "sha512-B6kpvqeD0ukTR7sydGKpktvO3VhZkOwQxAdLLGPdSHxQxREa2+sH6B9ODop6quPGjhmsZkJ/hL01rQ8At5xDew==", - "dev": true + "dev": true, + "license": "OFL-1.1" }, "node_modules/@intlify/core-base": { "version": "9.14.1", @@ -1585,6 +1878,29 @@ "url": "https://github.com/sponsors/kazupon" } }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1701,28 +2017,15 @@ "node": ">=18.0.0" } }, - "node_modules/@isaacs/fs-minipass/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -1730,45 +2033,104 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz", + "integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.2.0.tgz", + "integrity": "sha512-io1zEbbYcElht3tdlqEOFxZ0dMTYrHz9iMf0gqn1pPjZFTCgM5R4R5IMA20Chb2UPYYsxjzs8CgZ7Nb5n2K2rA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.6.0.tgz", + "integrity": "sha512-sw/RMbehRhN68WRtcKCpQOPfnH6lLP4GJfqzi3iYej8tnzpZUDr6UkZYJjcjjC0FWEJOJbyM3PTIwxucUmDG2A==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true, + "license": "MIT" + }, "node_modules/@malept/cross-spawn-promise": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", @@ -1824,13 +2186,27 @@ "node": ">=10" } }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "node_modules/@malept/flatpak-bundler/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-scope": "5.1.1" + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" } }, "node_modules/@npmcli/agent": { @@ -1850,44 +2226,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/@npmcli/agent/node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/@npmcli/agent/node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@npmcli/agent/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/@npmcli/agent/node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", @@ -1895,46 +2233,17 @@ "dev": true, "license": "ISC" }, - "node_modules/@npmcli/agent/node_modules/socks-proxy-agent": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", - "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-4.0.0.tgz", + "integrity": "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==", "dev": true, "license": "ISC", "dependencies": { - "@gar/promisify": "^1.1.3", "semver": "^7.3.5" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/@npmcli/move-file": { @@ -1952,12 +2261,30 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/@npmcli/move-file/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@parcel/watcher": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", - "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "dependencies": { "detect-libc": "^1.0.3", @@ -1973,29 +2300,30 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.0", - "@parcel/watcher-darwin-arm64": "2.5.0", - "@parcel/watcher-darwin-x64": "2.5.0", - "@parcel/watcher-freebsd-x64": "2.5.0", - "@parcel/watcher-linux-arm-glibc": "2.5.0", - "@parcel/watcher-linux-arm-musl": "2.5.0", - "@parcel/watcher-linux-arm64-glibc": "2.5.0", - "@parcel/watcher-linux-arm64-musl": "2.5.0", - "@parcel/watcher-linux-x64-glibc": "2.5.0", - "@parcel/watcher-linux-x64-musl": "2.5.0", - "@parcel/watcher-win32-arm64": "2.5.0", - "@parcel/watcher-win32-ia32": "2.5.0", - "@parcel/watcher-win32-x64": "2.5.0" + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" } }, "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz", - "integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -2009,13 +2337,14 @@ } }, "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz", - "integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -2029,13 +2358,14 @@ } }, "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz", - "integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -2049,13 +2379,14 @@ } }, "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz", - "integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -2069,13 +2400,14 @@ } }, "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz", - "integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2089,13 +2421,14 @@ } }, "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz", - "integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2109,13 +2442,14 @@ } }, "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz", - "integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2129,13 +2463,14 @@ } }, "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz", - "integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2149,13 +2484,14 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz", - "integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2169,13 +2505,14 @@ } }, "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz", - "integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2189,13 +2526,14 @@ } }, "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz", - "integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -2209,13 +2547,14 @@ } }, "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz", - "integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -2229,13 +2568,14 @@ } }, "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz", - "integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -2248,6 +2588,28 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/@parcel/watcher/node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2322,6 +2684,27 @@ "node": ">= 10" } }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -2335,6 +2718,27 @@ "@types/responselike": "^1.0.0" } }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -2350,6 +2754,7 @@ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -2360,16 +2765,44 @@ "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz", + "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } }, "node_modules/@types/fs-extra": { "version": "9.0.13", @@ -2385,7 +2818,8 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/http-cache-semantics": { "version": "4.0.4", @@ -2394,11 +2828,29 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.16", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz", + "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/keyv": { "version": "3.1.4", @@ -2410,6 +2862,13 @@ "@types/node": "*" } }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", @@ -2418,12 +2877,23 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "version": "24.0.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.13.tgz", + "integrity": "sha512-Qm9OYVOFHFYg3wJoTSrz80hoec5Lia/dPp84do3X7dZvLikQvM1YpmvTBEdIr/e+U8HTkFjLHLnl78K/qjf+jQ==", "dev": true, + "license": "MIT", "dependencies": { - "undici-types": "~6.20.0" + "undici-types": "~7.8.0" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.13.tgz", + "integrity": "sha512-zePQJSW5QkwSHKRApqWCVKeKoSOt4xvEnLENZPjyvm9Ezdf/EyDeJM7jqLzOwjVICQQzvLZ63T55MKdJB5H6ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" } }, "node_modules/@types/plist": { @@ -2438,6 +2908,20 @@ "xmlbuilder": ">=11.0.1" } }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/responselike": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", @@ -2448,6 +2932,56 @@ "@types/node": "*" } }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/verror": { "version": "1.10.11", "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.11.tgz", @@ -2456,6 +2990,16 @@ "license": "MIT", "optional": true }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -2554,20 +3098,6 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/@vue/component-compiler-utils/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@vue/component-compiler-utils/node_modules/prettier": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", @@ -2604,6 +3134,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" @@ -2613,25 +3144,29 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", @@ -2642,13 +3177,15 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -2661,6 +3198,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, + "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -2670,6 +3208,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } @@ -2678,13 +3217,15 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -2701,6 +3242,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", @@ -2714,6 +3256,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -2726,6 +3269,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", @@ -2740,6 +3284,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" @@ -2806,13 +3351,15 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/7zip-bin": { "version": "5.2.0", @@ -2822,17 +3369,45 @@ "license": "MIT" }, "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", "dev": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2840,32 +3415,43 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.3.tgz", + "integrity": "sha512-jtKLnfoOzm28PazuQ4dVBcE9Jeo6ha1GAJvq3N0LlNOszmTfx+wSycBehn+FN0RnyeR77IBxN/qVYMw0Rlj0Xw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, "license": "MIT", - "dependencies": { - "debug": "4" - }, "engines": { - "node": ">= 6.0.0" + "node": ">= 14" } }, "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2894,6 +3480,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2910,6 +3497,7 @@ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, @@ -2927,6 +3515,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -2942,13 +3531,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } @@ -2957,13 +3548,28 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/animate.css/-/animate.css-4.1.1.tgz", "integrity": "sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2973,6 +3579,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2983,6 +3590,20 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/app-builder-bin": { "version": "5.0.0-alpha.12", "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz", @@ -3068,16 +3689,6 @@ "node": ">=12.13.0" } }, - "node_modules/app-builder-lib/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/app-builder-lib/node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -3093,45 +3704,57 @@ "node": ">=12" } }, - "node_modules/app-builder-lib/node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "node_modules/app-builder-lib/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/app-builder-lib/node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", - "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=12" } }, - "node_modules/app-builder-lib/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "node_modules/app-builder-lib/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/app-builder-lib/node_modules/node-abi": { + "version": "3.75.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.75.0.tgz", + "integrity": "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" }, "engines": { "node": ">=10" } }, + "node_modules/app-builder-lib/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/app-builder-lib/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -3183,19 +3806,29 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true, + "license": "MIT" }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/assert-never": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.3.0.tgz", - "integrity": "sha512-9Z3vxQ+berkL/JJo0dK+EY3Lp0s3NtSnP3VCLsh5HDcZPrh0M+KQRK5sWhUeyPPH+/RCxZqOxLMR+YC6vlviEQ==", - "dev": true + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz", + "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==", + "dev": true, + "license": "MIT" }, "node_modules/assert-plus": { "version": "1.0.0", @@ -3266,13 +3899,15 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz", "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", "dev": true, + "license": "MIT", "dependencies": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" @@ -3283,6 +3918,7 @@ "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.9.6" }, @@ -3294,7 +3930,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -3317,15 +3954,36 @@ ], "license": "MIT" }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true, + "license": "MIT" + }, "node_modules/big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -3345,11 +4003,78 @@ "dev": true, "license": "MIT" }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/bonjour-service": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/boolean": { "version": "3.2.0", @@ -3361,10 +4086,11 @@ "optional": true }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3375,7 +4101,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, - "optional": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -3384,22 +4110,29 @@ } }, "node_modules/broker-factory": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.6.tgz", - "integrity": "sha512-yIQuvDXR1MzA758Y1YUonVdjL0ZDg8HIG4Eq5rzYcHSV6xxqB5JL2mkjnJY+4IjXyY7OhPaLejwleOOw6sABhQ==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.8.tgz", + "integrity": "sha512-xmVnYN0FZtynhPUmAnN+/MFRdbDi3syCuxWV7o7s78FcIN0pjDtn9mUrVqEgdjQkbfojRhlPWbYbXJkMCyddrg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.1", - "fast-unique-numbers": "^9.0.21", + "@babel/runtime": "^7.27.6", + "fast-unique-numbers": "^9.0.22", "tslib": "^2.8.1", - "worker-factory": "^7.0.42" + "worker-factory": "^7.0.44" } }, + "node_modules/broker-factory/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", "dev": true, "funding": [ { @@ -3417,10 +4150,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -3468,7 +4201,8 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/builder-util": { "version": "26.0.11", @@ -3510,82 +4244,200 @@ "node": ">=12.0.0" } }, - "node_modules/builder-util/node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/builder-util/node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "node_modules/builder-util/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">= 14" + "node": ">=12" } }, - "node_modules/builder-util/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "node_modules/builder-util/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/builder-util/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" }, "engines": { - "node": ">= 14" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, "node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", + "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", "dev": true, "license": "ISC", "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", + "@npmcli/fs": "^4.0.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "tar": "^7.4.3", + "unique-filename": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cacache/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, "node_modules/cacheable-lookup": { @@ -3617,25 +4469,6 @@ "node": ">=8" } }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -3650,6 +4483,23 @@ "node": ">= 0.4" } }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", @@ -3673,15 +4523,16 @@ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", "dev": true, + "license": "MIT", "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001700", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz", - "integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==", + "version": "1.0.30001727", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", + "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", "dev": true, "funding": [ { @@ -3704,6 +4555,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3720,15 +4572,17 @@ "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", "dev": true, + "license": "MIT", "dependencies": { "is-regex": "^1.0.3" } }, "node_modules/chokidar": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", - "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, + "license": "MIT", "dependencies": { "readdirp": "^4.0.1" }, @@ -3754,6 +4608,7 @@ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0" } @@ -3786,6 +4641,7 @@ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", "dev": true, + "license": "MIT", "dependencies": { "source-map": "~0.6.0" }, @@ -3921,6 +4777,7 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -3958,6 +4815,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3969,13 +4827,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", @@ -3991,12 +4851,13 @@ } }, "node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 12" + "node": ">= 6" } }, "node_modules/compare-version": { @@ -4009,11 +4870,71 @@ "node": ">=0.10.0" } }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/config-file-ts": { "version": "0.2.8-rc1", @@ -4027,9 +4948,9 @@ } }, "node_modules/config-file-ts/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4073,14 +4994,14 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/config-file-ts/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=0.8" } }, "node_modules/consolidate": { @@ -4102,17 +5023,51 @@ "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.6.0", "@babel/types": "^7.6.1" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, - "peer": true + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true, + "license": "MIT" }, "node_modules/copy-webpack-plugin": { "version": "13.0.0", @@ -4144,15 +5099,15 @@ "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", "dev": true, - "hasInstallScript": true + "hasInstallScript": true, + "license": "MIT" }, "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/crc": { "version": "3.8.0", @@ -4198,6 +5153,7 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -4212,6 +5168,7 @@ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", @@ -4242,23 +5199,12 @@ } } }, - "node_modules/css-loader/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/css-select": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", @@ -4271,10 +5217,11 @@ } }, "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -4287,6 +5234,7 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -4359,23 +5307,48 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deepmerge": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/default-passive-events": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/default-passive-events/-/default-passive-events-4.0.0.tgz", - "integrity": "sha512-0whk/GqfDOjc0AJIpacXUSqX6kV9TjL3GFSXIxFvuXQYcK+bEdJ6rpJnAEfP4YYMYWibM+jhlwmdlVrlifoepg==", + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/defaults": { "version": "1.0.4", @@ -4415,6 +5388,8 @@ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", + "optional": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -4427,6 +5402,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -4456,17 +5444,35 @@ "node": ">=0.4.0" } }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, - "optional": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, + "license": "MIT", "engines": { - "node": ">=0.10" + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" } }, "node_modules/detect-node": { @@ -4474,8 +5480,7 @@ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/dir-compare": { "version": "4.2.0", @@ -4488,6 +5493,19 @@ "p-limit": "^3.1.0 " } }, + "node_modules/dir-compare/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/dmg-builder": { "version": "26.0.12", "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.0.12.tgz", @@ -4506,6 +5524,44 @@ "dmg-license": "^1.0.11" } }, + "node_modules/dmg-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dmg-builder/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/dmg-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/dmg-license": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", @@ -4533,17 +5589,32 @@ "node": ">=8" } }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/doctypes": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", "dev": true, + "license": "MIT", "dependencies": { "utila": "~0.4" } @@ -4553,6 +5624,7 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -4572,13 +5644,15 @@ "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.2.0" }, @@ -4594,6 +5668,7 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -4608,15 +5683,16 @@ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -4675,12 +5751,12 @@ "zrender": "5.6.1" } }, - "node_modules/echarts/node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true, - "license": "0BSD" + "license": "MIT" }, "node_modules/ejs": { "version": "3.1.10", @@ -4699,9 +5775,9 @@ } }, "node_modules/electron": { - "version": "36.4.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-36.4.0.tgz", - "integrity": "sha512-LLOOZEuW5oqvnjC7HBQhIqjIIJAZCIFjQxltQGLfEC7XFsBoZgQ3u3iFj+Kzw68Xj97u1n57Jdt7P98qLvUibQ==", + "version": "37.2.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-37.2.1.tgz", + "integrity": "sha512-ae2EbzRNqIAHlftfCHtbbt6EgJUW8+zxWLONqNnn2iSrLF0O/pbxbff3xcpZYPpmFBs4uqjoi+s4QS7DQ+zZ/w==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4771,6 +5847,44 @@ "node": ">=12" } }, + "node_modules/electron-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-builder/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/electron-builder/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -4835,10 +5949,48 @@ "mime": "^2.5.2" } }, + "node_modules/electron-publish/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-publish/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-publish/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/electron-to-chromium": { - "version": "1.5.103", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.103.tgz", - "integrity": "sha512-P6+XzIkfndgsrjROJWfSvVEgNHtPgbhVyTkwLjUM2HU/h7pZRORgaTlHqfAikqxKmdJMLW8fftrdGWbd/Ds0FA==", + "version": "1.5.182", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.182.tgz", + "integrity": "sha512-Lv65Btwv9W4J9pyODI6EWpdnhfvrve/us5h1WspW8B2Fb0366REPtY3hX7ounk1CkV/TBjWCEvCBBbYbmV0qCA==", "dev": true, "license": "ISC" }, @@ -4880,33 +6032,29 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/electron-winstaller/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "node_modules/electron/node_modules/@types/node": { + "version": "22.16.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.3.tgz", + "integrity": "sha512-sr4Xz74KOUeYadexo1r8imhRtlVXcs+j3XK3TcoiYk7B1t3YRVJgtaD3cwX73NYb71pmVuMLNRhJ9XKdoDB74g==", "dev": true, "license": "MIT", - "peer": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "dependencies": { + "undici-types": "~6.21.0" } }, - "node_modules/electron-winstaller/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "node_modules/electron/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 4.0.0" - } + "license": "MIT" }, "node_modules/element-ui": { "version": "2.15.14", "resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.15.14.tgz", "integrity": "sha512-2v9fHL0ZGINotOlRIAJD5YuVB8V7WKxrE9Qy7dXhRipa035+kF7WuU/z+tEmLVPBcJ0zt8mOu1DKpWcVzBK8IA==", "dev": true, + "license": "MIT", "dependencies": { "async-validator": "~1.8.1", "babel-helper-vue-jsx-merge-props": "^2.0.0", @@ -4923,17 +6071,29 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/emojis-list": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/encoding": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", @@ -4946,9 +6106,9 @@ } }, "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", "dev": true, "license": "MIT", "dependencies": { @@ -4956,10 +6116,11 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", + "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -4973,6 +6134,7 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, + "license": "BSD-2-Clause", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -4992,6 +6154,7 @@ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", "dev": true, + "license": "MIT", "bin": { "envinfo": "dist/cli.js" }, @@ -5021,15 +6184,17 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "dev": true + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.1.1", @@ -5069,9 +6234,9 @@ "optional": true }, "node_modules/esbuild": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", - "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.6.tgz", + "integrity": "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -5082,31 +6247,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.0", - "@esbuild/android-arm": "0.25.0", - "@esbuild/android-arm64": "0.25.0", - "@esbuild/android-x64": "0.25.0", - "@esbuild/darwin-arm64": "0.25.0", - "@esbuild/darwin-x64": "0.25.0", - "@esbuild/freebsd-arm64": "0.25.0", - "@esbuild/freebsd-x64": "0.25.0", - "@esbuild/linux-arm": "0.25.0", - "@esbuild/linux-arm64": "0.25.0", - "@esbuild/linux-ia32": "0.25.0", - "@esbuild/linux-loong64": "0.25.0", - "@esbuild/linux-mips64el": "0.25.0", - "@esbuild/linux-ppc64": "0.25.0", - "@esbuild/linux-riscv64": "0.25.0", - "@esbuild/linux-s390x": "0.25.0", - "@esbuild/linux-x64": "0.25.0", - "@esbuild/netbsd-arm64": "0.25.0", - "@esbuild/netbsd-x64": "0.25.0", - "@esbuild/openbsd-arm64": "0.25.0", - "@esbuild/openbsd-x64": "0.25.0", - "@esbuild/sunos-x64": "0.25.0", - "@esbuild/win32-arm64": "0.25.0", - "@esbuild/win32-ia32": "0.25.0", - "@esbuild/win32-x64": "0.25.0" + "@esbuild/aix-ppc64": "0.25.6", + "@esbuild/android-arm": "0.25.6", + "@esbuild/android-arm64": "0.25.6", + "@esbuild/android-x64": "0.25.6", + "@esbuild/darwin-arm64": "0.25.6", + "@esbuild/darwin-x64": "0.25.6", + "@esbuild/freebsd-arm64": "0.25.6", + "@esbuild/freebsd-x64": "0.25.6", + "@esbuild/linux-arm": "0.25.6", + "@esbuild/linux-arm64": "0.25.6", + "@esbuild/linux-ia32": "0.25.6", + "@esbuild/linux-loong64": "0.25.6", + "@esbuild/linux-mips64el": "0.25.6", + "@esbuild/linux-ppc64": "0.25.6", + "@esbuild/linux-riscv64": "0.25.6", + "@esbuild/linux-s390x": "0.25.6", + "@esbuild/linux-x64": "0.25.6", + "@esbuild/netbsd-arm64": "0.25.6", + "@esbuild/netbsd-x64": "0.25.6", + "@esbuild/openbsd-arm64": "0.25.6", + "@esbuild/openbsd-x64": "0.25.6", + "@esbuild/openharmony-arm64": "0.25.6", + "@esbuild/sunos-x64": "0.25.6", + "@esbuild/win32-arm64": "0.25.6", + "@esbuild/win32-ia32": "0.25.6", + "@esbuild/win32-x64": "0.25.6" } }, "node_modules/esbuild-loader": { @@ -5128,46 +6294,29 @@ "webpack": "^4.40.0 || ^5.0.0" } }, - "node_modules/esbuild-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/esbuild-loader/node_modules/webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -5176,19 +6325,19 @@ } }, "node_modules/eslint": { - "version": "9.28.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz", - "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==", + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.31.0.tgz", + "integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.1", - "@eslint/core": "^0.14.0", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.15.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.28.0", + "@eslint/js": "9.31.0", "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -5200,9 +6349,9 @@ "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -5253,9 +6402,9 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "9.32.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.32.0.tgz", - "integrity": "sha512-b/Y05HYmnB/32wqVcjxjHZzNpwxj1onBOvqW89W+V+XNG1dRuaFbNd3vT9CLbr2LXjEoq+3vn8DanWf7XU22Ug==", + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.33.0.tgz", + "integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==", "dev": true, "license": "MIT", "dependencies": { @@ -5291,33 +6440,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-vue/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-vue/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint-plugin-vue/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -5332,31 +6454,9 @@ } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", - "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -5370,11 +6470,12 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -5382,26 +6483,29 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "BSD-2-Clause", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=4.0" + "node": "*" } }, "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.14.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" + "eslint-visitor-keys": "^4.2.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5410,24 +6514,12 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -5435,20 +6527,12 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -5456,20 +6540,12 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -5479,26 +6555,109 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.x" } }, "node_modules/exponential-backoff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz", + "integrity": "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==", "dev": true, "license": "Apache-2.0" }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "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" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -5535,49 +6694,84 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-unique-numbers": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.21.tgz", - "integrity": "sha512-t7gFR4sftDWVSBCL65ByTxR5Tf6c1hLPCoNZL3K9Jq5zBb3FY8jGffSvRdY6nVgm8reGq8Ii39Mm6YePX7uKAA==", + "version": "9.0.22", + "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.22.tgz", + "integrity": "sha512-dBR+30yHAqBGvOuxxQdnn2lTLHCO6r/9B+M4yF8mNrzr3u1yiF+YVJ6u3GTyPN/VRWqaE1FcscZDdBgVKmrmQQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.1", + "@babel/runtime": "^7.27.6", "tslib": "^2.8.1" }, "engines": { "node": ">=18.2.0" } }, + "node_modules/fast-unique-numbers/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/fast-uri": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", - "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", - "dev": true + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4.9.1" } }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -5593,6 +6787,7 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" }, @@ -5611,9 +6806,9 @@ } }, "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5638,7 +6833,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, - "optional": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -5646,11 +6841,48 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -5677,6 +6909,7 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" @@ -5686,10 +6919,32 @@ } }, "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", - "dev": true + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } }, "node_modules/foreground-child": { "version": "3.3.1", @@ -5722,47 +6977,68 @@ } }, "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", + "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { "node": ">= 6" } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": ">=12" + "node": ">=6 <7 || >=8" } }, "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, "license": "ISC", "dependencies": { - "minipass": "^3.0.0" + "minipass": "^7.0.3" }, "engines": { - "node": ">= 8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/fs.realpath": { @@ -5772,30 +7048,37 @@ "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -5869,9 +7152,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", - "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5882,9 +7165,9 @@ } }, "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", @@ -5892,11 +7175,12 @@ "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">=12" + "node": "*" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -5907,6 +7191,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -5918,29 +7203,20 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } + "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=10" + "node": "*" } }, "node_modules/global-agent": { @@ -5962,28 +7238,17 @@ "node": ">=10.0" } }, - "node_modules/global-agent/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz", + "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==", "dev": true, - "peer": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globalthis": { @@ -6047,13 +7312,22 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true, + "license": "MIT" }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -6063,6 +7337,8 @@ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", + "optional": true, "dependencies": { "es-define-property": "^1.0.0" }, @@ -6088,6 +7364,7 @@ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" }, @@ -6110,6 +7387,7 @@ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -6131,6 +7409,7 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, + "license": "MIT", "bin": { "he": "bin/he" } @@ -6142,6 +7421,7 @@ "deprecated": "Support has ended for 9.x series. Upgrade to @latest", "dev": true, "hasInstallScript": true, + "license": "BSD-3-Clause", "engines": { "node": "*" } @@ -6159,31 +7439,58 @@ "node": ">=10" } }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" } }, - "node_modules/hosted-git-info/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } }, "node_modules/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", "dev": true, + "license": "MIT", "dependencies": { "camel-case": "^4.1.2", "clean-css": "^5.2.2", @@ -6200,11 +7507,22 @@ "node": ">=12" } }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/html-webpack-plugin": { "version": "5.6.3", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", "dev": true, + "license": "MIT", "dependencies": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", @@ -6244,6 +7562,7 @@ "url": "https://github.com/sponsors/fb55" } ], + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.0.0", @@ -6252,25 +7571,95 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "dev": true, "license": "BSD-2-Clause" }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "engines": { - "node": ">= 6" + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } } }, "node_modules/http2-wrapper": { @@ -6288,17 +7677,17 @@ } }, "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "6", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/humanize-ms": { @@ -6311,6 +7700,16 @@ "ms": "^2.0.0" } }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.18" + } + }, "node_modules/iconv-corefoundation": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", @@ -6329,14 +7728,6 @@ "node": "^8.11.2 || >=10" } }, - "node_modules/iconv-corefoundation/node_modules/node-addon-api": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", - "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -6355,6 +7746,7 @@ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -6394,10 +7786,11 @@ } }, "node_modules/immutable": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz", - "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", - "dev": true + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", + "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", + "dev": true, + "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.1", @@ -6421,6 +7814,7 @@ "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -6440,6 +7834,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -6485,6 +7880,7 @@ "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.13.0" } @@ -6503,12 +7899,28 @@ "node": ">= 12" } }, - "node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, - "license": "BSD-3-Clause" + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/is-ci": { "version": "3.0.1", @@ -6524,10 +7936,11 @@ } }, "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -6538,11 +7951,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-expression": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", "dev": true, + "license": "MIT", "dependencies": { "acorn": "^7.1.1", "object-assign": "^4.1.1" @@ -6553,6 +7983,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -6565,6 +7996,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6574,6 +8006,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -6583,6 +8016,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -6590,6 +8024,25 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -6607,16 +8060,42 @@ "dev": true, "license": "MIT" }, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "optional": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -6634,16 +8113,20 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -6665,6 +8148,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, "node_modules/isbinaryfile": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.4.tgz", @@ -6682,7 +8188,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/isobject": { "version": "3.0.1", @@ -6729,6 +8236,19 @@ "node": ">=10" } }, + "node_modules/jake/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -6764,20 +8284,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, - "peer": true + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -6792,42 +8307,33 @@ "dev": true, "license": "MIT" }, - "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, - "peer": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", @@ -6842,6 +8348,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -6850,14 +8357,11 @@ } }, "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -6867,6 +8371,7 @@ "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", "dev": true, + "license": "MIT", "dependencies": { "is-promise": "^2.0.0", "promise": "^7.0.1" @@ -6877,6 +8382,7 @@ "resolved": "https://registry.npmjs.org/katex/-/katex-0.6.0.tgz", "integrity": "sha512-rS4mY3SvHYg5LtQV6RBcK0if7ur6plyEukAOV+jGGPqFImuzu8fHL6M752iBmRGoUyF0bhZbAPoezehn7xYksA==", "dev": true, + "license": "MIT", "dependencies": { "match-at": "^0.1.0" }, @@ -6889,6 +8395,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -6903,6 +8410,17 @@ "node": ">=0.10.0" } }, + "node_modules/launch-editor": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz", + "integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, "node_modules/lazy-val": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", @@ -6915,6 +8433,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -6928,6 +8447,7 @@ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz", "integrity": "sha512-eGHwtlABkp1NOJSiKUNqBf3SYAS5jPHtvRXPAgNaQwTqmkTahjtiLH9NtxdR5IOPhNvwNMN/diswSfZKzUkhGg==", "dev": true, + "license": "MIT", "dependencies": { "uc.micro": "^1.0.1" } @@ -6937,34 +8457,24 @@ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.11.5" } }, "node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "json5": "^2.1.2" }, "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/loader-utils/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" + "node": ">=8.9.0" } }, "node_modules/locate-path": { @@ -6972,6 +8482,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -6986,13 +8497,15 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", @@ -7016,6 +8529,7 @@ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -7031,51 +8545,39 @@ } }, "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "peer": true, + "license": "ISC", "dependencies": { - "yallist": "^3.0.2" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, "node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", + "integrity": "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==", "dev": true, "license": "ISC", "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", + "@npmcli/agent": "^3.0.0", + "cacache": "^19.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", + "negotiator": "^1.0.0", + "proc-log": "^5.0.0", "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" + "ssri": "^12.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/markdown-it": { @@ -7083,6 +8585,7 @@ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-6.1.1.tgz", "integrity": "sha512-woFl7h/sqt9xRmiMweNuO7nu+w8Lz3SXsDlvE3TYeu1SdPqQ+VW4GZyaKP442Bq6XUN6V6IQjJTR93RDYG2mjw==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "entities": "~1.1.1", @@ -7098,37 +8601,43 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/markdown-it-abbr/-/markdown-it-abbr-1.0.4.tgz", "integrity": "sha512-ZeA4Z4SaBbYysZap5iZcxKmlPL6bYA8grqhzJIHB1ikn7njnzaP8uwbtuXc4YXD5LicI4/2Xmc0VwmSiFV04gg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/markdown-it-deflist": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/markdown-it-deflist/-/markdown-it-deflist-2.1.0.tgz", "integrity": "sha512-3OuqoRUlSxJiuQYu0cWTLHNhhq2xtoSFqsZK8plANg91+RJQU1ziQ6lA2LzmFAEes18uPBsHZpcX6We5l76Nzg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/markdown-it-emoji": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", "integrity": "sha512-QCz3Hkd+r5gDYtS2xsFXmBYrgw6KuWcJZLCEkdfAuwzZbShCmCfta+hwAMq4NX/4xPzkSHduMKgMkkPUJxSXNg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/markdown-it-footnote": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-2.0.0.tgz", "integrity": "sha512-GMWkJXSHh5tiQt77zCLOSZI2Xy3Oqdb82GmT0Q0h2UT6SbUrMCAiHEiMBIt5V7Xfm73rBxS0VOhlLndkn1GPnw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/markdown-it-ins": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-2.0.0.tgz", "integrity": "sha512-DhLLxseIg2C7+AULvoyVI+zMeufR0QFvXJ2o0oV013hN5HvBvNh2rbVtTdxZjI959+hgo2AA0aRdtEIUaKPbhg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/markdown-it-katex": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/markdown-it-katex/-/markdown-it-katex-2.0.3.tgz", "integrity": "sha512-nUkkMtRWeg7OpdflamflE/Ho/pWl64Lk9wNBKOmaj33XkQdumhXAIYhI0WO03GeiycPCsxbmX536V5NEXpC3Ng==", "dev": true, + "license": "MIT", "dependencies": { "katex": "^0.6.0" } @@ -7137,31 +8646,36 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-2.0.0.tgz", "integrity": "sha512-iT8ua0Bda8QrVwHDOUNw1eyCuL7irXeYch5n8zGS4tb7wsDIn7EjQZLjihKaijzBiL0ikfWL2zAvL/ECqTvsNA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/markdown-it-sub": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz", "integrity": "sha512-z2Rm/LzEE1wzwTSDrI+FlPEveAAbgdAdPhdWarq/ZGJrGW/uCQbKAnhoCsE4hAbc3SEym26+W2z/VQB0cQiA9Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/markdown-it-sup": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz", "integrity": "sha512-E32m0nV9iyhRR7CrhnzL5msqic7rL1juWre6TQNxsnApg7Uf+F97JOKxUijg5YwXz86lZ0mqfOnutoryyNdntQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/markdown-it-task-lists": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/markdown-it-task-lists/-/markdown-it-task-lists-2.1.1.tgz", "integrity": "sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/markdown-it-toc-and-anchor": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/markdown-it-toc-and-anchor/-/markdown-it-toc-and-anchor-4.2.0.tgz", "integrity": "sha512-DusSbKtg8CwZ92ztN7bOojDpP4h0+w7BVOPuA3PHDIaabMsERYpwsazLYSP/UlKedoQjOz21mwlai36TQ04EpA==", "dev": true, + "license": "MIT", "dependencies": { "clone": "^2.1.0", "uslug": "^1.0.4" @@ -7172,6 +8686,7 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } @@ -7180,7 +8695,15 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/markdown-it/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/match-at": { "version": "0.1.1", @@ -7216,7 +8739,48 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.17.2.tgz", + "integrity": "sha512-NgYhCOWgovOXSzvYgUW0LQ7Qy72rWQMGGFJDoWg4G30RHd3z77VbYdtJ4fembJXBy8pMIUA31XNAupobOQlwdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-source-map": { "version": "1.1.0", @@ -7235,12 +8799,22 @@ "dev": true, "license": "MIT" }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, - "optional": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -7267,6 +8841,7 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -7276,6 +8851,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -7308,6 +8884,7 @@ "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", "integrity": "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==", "dev": true, + "license": "MIT", "dependencies": { "schema-utils": "^4.0.0", "tapable": "^2.2.1" @@ -7323,16 +8900,27 @@ "webpack": "^5.0.0" } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true, + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "@isaacs/brace-expansion": "^5.0.0" }, "engines": { - "node": "*" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -7340,49 +8928,47 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" } }, "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, "license": "ISC", "dependencies": { - "minipass": "^3.0.0" + "minipass": "^7.0.3" }, "engines": { - "node": ">= 8" + "node": ">=16 || 14 >=14.17" } }, "node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-4.0.1.tgz", + "integrity": "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==", "dev": true, "license": "MIT", "dependencies": { - "minipass": "^3.1.6", + "minipass": "^7.0.3", "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" + "minizlib": "^3.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" }, "optionalDependencies": { "encoding": "^0.1.13" @@ -7401,6 +8987,19 @@ "node": ">= 8" } }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", @@ -7414,6 +9013,19 @@ "node": ">=8" } }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", @@ -7427,33 +9039,31 @@ "node": ">=8" } }, - "node_modules/minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "license": "ISC" - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "minipass": "^3.0.0", "yallist": "^4.0.0" }, "engines": { - "node": ">= 8" + "node": ">=8" } }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } }, "node_modules/mkdirp": { "version": "1.0.4", @@ -7472,12 +9082,27 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -7485,6 +9110,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -7496,12 +9122,13 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "dev": true, "license": "MIT", "engines": { @@ -7512,55 +9139,45 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dev": true, + "license": "MIT", "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, "node_modules/node-abi": { - "version": "3.71.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.71.0.tgz", - "integrity": "sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.12.0.tgz", + "integrity": "sha512-bPSN9a/qIEiURzVVO/I7P/8oPeYTSl+vnvVZBXM/8XerKOgA3dMAIUjl+a+lz9VwTowwSKS3EMsgz/vWDXOkuQ==", "dev": true, "license": "MIT", "dependencies": { - "semver": "^7.3.5" + "semver": "^7.6.3" }, "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "node": ">=22.12.0" } }, "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/node-api-dotnet": { - "version": "0.9.11", - "resolved": "https://registry.npmjs.org/node-api-dotnet/-/node-api-dotnet-0.9.11.tgz", - "integrity": "sha512-TdVd8zlsWFqVyY8W7W6xM/kpD3JZFcRNyx7X4isRqiCCA1i0JTef0/hbxnPA8cyCfA+vx7HHIyuSuykdUjfzig==", + "version": "0.9.12", + "resolved": "https://registry.npmjs.org/node-api-dotnet/-/node-api-dotnet-0.9.12.tgz", + "integrity": "sha512-qa0XNHe0qdpNo2WECBg8wICcF7a7JAVgVTsJcG3w9na2KjpqrT3aOzR/pCZIsqSRvUR3OqrIrx8yNw4flya2Cw==", "license": "MIT" }, "node_modules/node-api-version": { @@ -7573,17 +9190,14 @@ "semver": "^7.3.5" } }, - "node_modules/node-api-version/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { - "node": ">=10" + "node": ">= 6.13.0" } }, "node_modules/node-gyp": { @@ -7611,63 +9225,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/node-gyp/node_modules/@npmcli/fs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-4.0.0.tgz", - "integrity": "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/node-gyp/node_modules/abbrev": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", - "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/node-gyp/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/node-gyp/node_modules/cacache": { - "version": "19.0.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", - "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^4.0.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^12.0.0", - "tar": "^7.4.3", - "unique-filename": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, "node_modules/node-gyp/node_modules/chownr": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", @@ -7678,40 +9235,6 @@ "node": ">=18" } }, - "node_modules/node-gyp/node_modules/fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-gyp/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/node-gyp/node_modules/isexe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", @@ -7722,106 +9245,6 @@ "node": ">=16" } }, - "node_modules/node-gyp/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/node-gyp/node_modules/make-fetch-happen": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", - "integrity": "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/agent": "^3.0.0", - "cacache": "^19.0.1", - "http-cache-semantics": "^4.1.1", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^1.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "ssri": "^12.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/node-gyp/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/node-gyp/node_modules/minipass-collect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/node-gyp/node_modules/minipass-fetch": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-4.0.1.tgz", - "integrity": "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/node-gyp/node_modules/minizlib": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", - "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/node-gyp/node_modules/mkdirp": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", @@ -7838,81 +9261,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/node-gyp/node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-gyp/node_modules/nopt": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", - "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", - "dev": true, - "license": "ISC", - "dependencies": { - "abbrev": "^3.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/node-gyp/node_modules/p-map": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", - "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/node-gyp/node_modules/proc-log": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", - "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/node-gyp/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/ssri": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", - "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, "node_modules/node-gyp/node_modules/tar": { "version": "7.4.3", "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", @@ -7931,32 +9279,6 @@ "node": ">=18" } }, - "node_modules/node-gyp/node_modules/unique-filename": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", - "integrity": "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/node-gyp/node_modules/unique-slug": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", - "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, "node_modules/node-gyp/node_modules/which": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", @@ -7991,19 +9313,19 @@ "license": "MIT" }, "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", "dev": true, "license": "ISC", "dependencies": { - "abbrev": "^1.0.0" + "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/normalize-path": { @@ -8011,6 +9333,7 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8032,26 +9355,23 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", "integrity": "sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==", - "dev": true - }, - "node_modules/normalize.css": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", - "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/noty": { "version": "3.2.0-beta-deprecated", "resolved": "https://registry.npmjs.org/noty/-/noty-3.2.0-beta-deprecated.tgz", "integrity": "sha512-ntRbHuQ9SnnnVFZm/oq5L1DBCaHQUvsU24AwZH3PGjAWx2YqR/IhOadMk11vmJovYiQo00oqTj6Hp+D6PGtmLA==", "deprecated": "no longer supported", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -8064,10 +9384,24 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -8079,6 +9413,36 @@ "node": ">= 0.4" } }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -8105,11 +9469,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.2.tgz", + "integrity": "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -8161,6 +9545,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -8176,6 +9561,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -8187,26 +9573,52 @@ } }, "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", + "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", "dev": true, "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-retry": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -8223,6 +9635,7 @@ "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", "dev": true, + "license": "MIT", "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -8241,11 +9654,22 @@ "node": ">=6" } }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/pascal-case": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -8256,6 +9680,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8275,6 +9700,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8283,7 +9709,8 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", @@ -8309,15 +9736,12 @@ "dev": true, "license": "ISC" }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } + "license": "MIT" }, "node_modules/pe-library": { "version": "0.4.1", @@ -8345,14 +9769,15 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "optional": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -8360,11 +9785,35 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pinia": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz", + "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.3", + "vue-demi": "^0.14.10" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.4.4", + "vue": "^2.7.0 || ^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -8377,6 +9826,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -8390,6 +9840,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -8402,6 +9853,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -8417,6 +9869,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -8440,9 +9893,9 @@ } }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { @@ -8458,8 +9911,9 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -8472,6 +9926,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -8480,10 +9935,11 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.1.0.tgz", - "integrity": "sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^7.0.0", @@ -8496,11 +9952,26 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-modules-scope": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", "dev": true, + "license": "ISC", "dependencies": { "postcss-selector-parser": "^7.0.0" }, @@ -8511,11 +9982,26 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-modules-values": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, + "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" }, @@ -8527,10 +10013,11 @@ } }, "node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -8543,7 +10030,8 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/postject": { "version": "1.0.0-alpha.6", @@ -8580,14 +10068,15 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", "bin": { @@ -8605,21 +10094,29 @@ "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", "dev": true, + "license": "MIT", "dependencies": { "lodash": "^4.17.20", "renderkid": "^3.0.0" } }, "node_modules/proc-log": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", - "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", + "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", "dev": true, "license": "ISC", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -8635,6 +10132,7 @@ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "dev": true, + "license": "MIT", "dependencies": { "asap": "~2.0.3" } @@ -8660,6 +10158,30 @@ "node": ">=10" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -8672,6 +10194,7 @@ "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz", "integrity": "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==", "dev": true, + "license": "MIT", "dependencies": { "pug-code-gen": "^3.0.3", "pug-filters": "^4.0.0", @@ -8688,6 +10211,7 @@ "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", "dev": true, + "license": "MIT", "dependencies": { "constantinople": "^4.0.1", "js-stringify": "^1.0.2", @@ -8699,6 +10223,7 @@ "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.3.tgz", "integrity": "sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==", "dev": true, + "license": "MIT", "dependencies": { "constantinople": "^4.0.1", "doctypes": "^1.1.0", @@ -8714,13 +10239,15 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pug-filters": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", "dev": true, + "license": "MIT", "dependencies": { "constantinople": "^4.0.1", "jstransformer": "1.0.0", @@ -8734,6 +10261,7 @@ "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", "dev": true, + "license": "MIT", "dependencies": { "character-parser": "^2.2.0", "is-expression": "^4.0.0", @@ -8745,6 +10273,7 @@ "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", "dev": true, + "license": "MIT", "dependencies": { "pug-error": "^2.0.0", "pug-walk": "^2.0.0" @@ -8755,6 +10284,7 @@ "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", "dev": true, + "license": "MIT", "dependencies": { "object-assign": "^4.1.1", "pug-walk": "^2.0.0" @@ -8765,6 +10295,7 @@ "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", "dev": true, + "license": "MIT", "dependencies": { "pug-error": "^2.0.0", "token-stream": "1.0.0" @@ -8775,6 +10306,7 @@ "resolved": "https://registry.npmjs.org/pug-plain-loader/-/pug-plain-loader-1.1.0.tgz", "integrity": "sha512-1nYgIJLaahRuHJHhzSPODV44aZfb00bO7kiJiMkke6Hj4SVZftuvx6shZ4BOokk50dJc2RSFqNUBOlus0dniFQ==", "dev": true, + "license": "MIT", "dependencies": { "loader-utils": "^1.1.0" }, @@ -8782,17 +10314,47 @@ "pug": "^2.0.0 || ^3.0.0" } }, + "node_modules/pug-plain-loader/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/pug-plain-loader/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/pug-runtime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pug-strip-comments": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", "dev": true, + "license": "MIT", "dependencies": { "pug-error": "^2.0.0" } @@ -8801,12 +10363,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pump": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", - "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", "dev": true, "license": "MIT", "dependencies": { @@ -8819,10 +10382,27 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -8841,15 +10421,56 @@ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/raw-loader": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", "dev": true, + "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", "schema-utils": "^3.0.0" @@ -8865,25 +10486,12 @@ "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/raw-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, "node_modules/raw-loader/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -8926,12 +10534,13 @@ } }, "node_modules/readdirp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", - "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 14.16.0" + "node": ">= 14.18.0" }, "funding": { "type": "individual", @@ -8943,6 +10552,7 @@ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, + "license": "MIT", "dependencies": { "resolve": "^1.20.0" }, @@ -8954,13 +10564,15 @@ "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -8970,6 +10582,7 @@ "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", "dev": true, + "license": "MIT", "dependencies": { "css-select": "^4.1.3", "dom-converter": "^0.2.0", @@ -8993,10 +10606,18 @@ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, "node_modules/resedit": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/resedit/-/resedit-1.7.2.tgz", @@ -9019,21 +10640,26 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9050,6 +10676,7 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -9062,6 +10689,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -9124,42 +10752,18 @@ } }, "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" } }, "node_modules/roarr": { @@ -9181,13 +10785,18 @@ "node": ">=8.0" } }, - "node_modules/roarr/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", "dev": true, - "license": "BSD-3-Clause", - "optional": true + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/safe-buffer": { "version": "5.2.1", @@ -9207,7 +10816,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -9227,9 +10837,9 @@ } }, "node_modules/sass": { - "version": "1.89.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.1.tgz", - "integrity": "sha512-eMLLkl+qz7tx/0cJ9wI+w09GQ2zodTkcE/aVfywwdlRcI3EO19xGnbmJwg/JMIm+5MxVJ6outddLZ4Von4E++Q==", + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.2.tgz", + "integrity": "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==", "dev": true, "license": "MIT", "dependencies": { @@ -9320,6 +10930,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -9336,6 +10947,7 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -9347,15 +10959,41 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true, + "license": "MIT" + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } }, "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/semver-compare": { @@ -9366,6 +11004,71 @@ "license": "MIT", "optional": true }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/serialize-error": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", @@ -9388,27 +11091,120 @@ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, + "license": "MIT", "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" }, "engines": { - "node": ">= 0.4" + "node": ">= 0.8.0" } }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true, + "license": "ISC" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -9427,6 +11223,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -9439,10 +11236,100 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -9463,19 +11350,6 @@ "node": ">=10" } }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/slice-ansi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", @@ -9503,10 +11377,22 @@ "npm": ">= 3.0.0" } }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.6.tgz", + "integrity": "sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA==", "dev": true, "license": "MIT", "dependencies": { @@ -9519,18 +11405,18 @@ } }, "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" }, "engines": { - "node": ">= 10" + "node": ">= 14" } }, "node_modules/source-list-map": { @@ -9545,6 +11431,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -9554,6 +11441,7 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -9563,28 +11451,62 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", + "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", "dev": true, "license": "ISC", "dependencies": { - "minipass": "^3.1.1" + "minipass": "^7.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/stat-mode": { @@ -9597,6 +11519,16 @@ "node": ">= 6" } }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -9612,6 +11544,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9642,6 +11575,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -9694,6 +11628,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -9706,6 +11641,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -9714,10 +11650,11 @@ } }, "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -9740,6 +11677,32 @@ "node": ">=10" } }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tar/node_modules/minipass": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", @@ -9750,12 +11713,32 @@ "node": ">=8" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/tar/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/temp": { "version": "0.9.4", @@ -9783,27 +11766,42 @@ "fs-extra": "^10.0.0" } }, - "node_modules/temp/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/temp-file/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, - "license": "ISC", - "peer": true, + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": "*" + "node": ">=12" + } + }, + "node_modules/temp-file/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/temp-file/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" } }, "node_modules/temp/node_modules/mkdirp": { @@ -9820,29 +11818,15 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/temp/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/terser": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", - "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "version": "5.43.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", + "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -9854,9 +11838,9 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.11", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz", - "integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==", + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", "dev": true, "license": "MIT", "dependencies": { @@ -9892,17 +11876,39 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "dev": true, + "license": "Unlicense", + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" + } }, "node_modules/throttle-debounce": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz", "integrity": "sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true, + "license": "MIT" + }, "node_modules/tiny-async-pool": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", @@ -9924,13 +11930,13 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", - "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dev": true, "license": "MIT", "dependencies": { - "fdir": "^6.4.3", + "fdir": "^6.4.4", "picomatch": "^4.0.2" }, "engines": { @@ -9941,9 +11947,9 @@ } }, "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dev": true, "license": "MIT", "peerDependencies": { @@ -9993,7 +11999,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "optional": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -10001,11 +12007,39 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, "node_modules/token-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/tree-dump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.3.tgz", + "integrity": "sha512-il+Cv80yVHFBwokQSfd4bldvr1Md951DpgAGfmhydt04L+YzHgubm2tQ7zueWDcGENKHq0ZvGFR/hjvNXilHEg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } }, "node_modules/truncate-utf8-bytes": { "version": "1.0.2", @@ -10018,16 +12052,18 @@ } }, "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "dev": true, + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -10049,6 +12085,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", @@ -10067,48 +12117,50 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "dev": true, + "license": "MIT" }, "node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", + "integrity": "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==", "dev": true, "license": "ISC", "dependencies": { - "unique-slug": "^3.0.0" + "unique-slug": "^5.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", + "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 10.0.0" + "node": ">= 4.0.0" } }, "node_modules/unorm": { @@ -10116,14 +12168,25 @@ "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==", "dev": true, + "license": "MIT or GPL-2.0", "engines": { "node": ">= 0.4.0" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -10139,9 +12202,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -10155,6 +12219,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -10182,13 +12247,45 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/utila": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/verror": { "version": "1.10.1", @@ -10211,6 +12308,7 @@ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -10342,29 +12440,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/vue-eslint-parser/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/vue-eslint-parser/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/vue-hot-reload-api": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", @@ -10376,7 +12451,9 @@ "version": "8.28.2", "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.28.2.tgz", "integrity": "sha512-C5GZjs1tYlAqjwymaaCPDjCyGo10ajUphiwA922jKt9n7KPpqR7oM1PCwYzhB/E7+nT3wfdG3oRre5raIT1rKA==", - "dev": true + "deprecated": "Vue I18n v8.x has reached EOL and is no longer actively maintained. About maintenance status, see https://vue-i18n.intlify.dev/guide/maintenance.html", + "dev": true, + "license": "MIT" }, "node_modules/vue-i18n-bridge": { "version": "9.14.1", @@ -10407,10 +12484,11 @@ } }, "node_modules/vue-lazyload": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.3.4.tgz", - "integrity": "sha512-K0frbPQJuvFHVpdl/ov5CqCR/CHWeLGs8E8V1d/09DIETqBjeGhC1fLMmwUy3Go2Yd/VX610AZ7Mdn4B54592Q==", - "dev": true + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.3.5.tgz", + "integrity": "sha512-SCO/LWgCCbjaregHO4wg2buzITBdPBZRlIS104vERGpT88uxXsK26veuzZpgGAXMR8WpkaR+JDqz80OedpaLiA==", + "dev": true, + "license": "MIT" }, "node_modules/vue-loader": { "version": "15.11.1", @@ -10441,11 +12519,40 @@ } } }, + "node_modules/vue-loader/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/vue-loader/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/vue-markdown": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/vue-markdown/-/vue-markdown-2.2.4.tgz", "integrity": "sha512-hoTX/W1UIdHZrp/b0vpHSsJXAEfWsafaQLgtE2VX4gY8O/C3L2Gabqu95gyG429rL4ML1SwGv+xsPABX7yfFIQ==", "dev": true, + "license": "MIT", "dependencies": { "highlight.js": "^9.12.0", "markdown-it": "^6.0.1", @@ -10467,17 +12574,19 @@ "resolved": "https://registry.npmjs.org/vue-marquee-text-component/-/vue-marquee-text-component-1.2.0.tgz", "integrity": "sha512-wMqr7AnyCF1VjXFAnAXavAD2yCeiBULy6AbLet/YIGaI2KzuaUmi+Q3UyFYJOM2gWt994jl2PWilnkh9heLqAA==", "dev": true, + "license": "MIT", "dependencies": { "core-js": "^3.6.5", "vue": "^2.5.17" } }, "node_modules/vue-marquee-text-component/node_modules/core-js": { - "version": "3.39.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", - "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", + "version": "3.44.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.44.0.tgz", + "integrity": "sha512-aFCtd4l6GvAXwVEh3XbbVqJGHDJt0OZRa+5ePGx3LLwi12WfexqQxcsohb2wgsa/92xtl19Hd66G/L+TaAxDMw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -10494,6 +12603,34 @@ "loader-utils": "^1.0.2" } }, + "node_modules/vue-style-loader/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/vue-style-loader/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/vue-template-es2015-compiler": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", @@ -10502,10 +12639,11 @@ "license": "MIT" }, "node_modules/watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", + "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", "dev": true, + "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -10514,6 +12652,16 @@ "node": ">=10.13.0" } }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -10525,22 +12673,23 @@ } }, "node_modules/webpack": { - "version": "5.99.9", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz", - "integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==", + "version": "5.100.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.100.1.tgz", + "integrity": "sha512-YJB/ESPUe2Locd0NKXmw72Dx8fZQk1gTzI6rc9TAT4+Sypbnhl8jd8RywB1bDsDF9Dy1RUR7gn3q/ZJTd0OZZg==", "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", + "@types/estree": "^1.0.8", "@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.0", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", + "enhanced-resolve": "^5.17.2", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -10554,7 +12703,7 @@ "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -10625,6 +12774,145 @@ "node": ">=18" } }, + "node_modules/webpack-dev-middleware": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", + "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.6.0", + "mime-types": "^2.1.31", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.2.tgz", + "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/express-serve-static-core": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "express": "^4.21.2", + "graceful-fs": "^4.2.6", + "http-proxy-middleware": "^2.0.9", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/webpack-dev-server/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/webpack-dev-server/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/webpack-merge": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", @@ -10641,19 +12929,81 @@ } }, "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "dev": true, + "license": "MIT", + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/webpack/node_modules/webpack-sources": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=10.13.0" } }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -10676,6 +13026,7 @@ "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.9.6", "@babel/types": "^7.9.6", @@ -10691,61 +13042,90 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/worker-factory": { - "version": "7.0.42", - "resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.42.tgz", - "integrity": "sha512-xQhdcRafZFHGxX+EpJqXsY1X5czW95XN7aXP+0cmy6RMX/8+r78znLyJB7DafPTIFdyNk09J6wstW0RreIlIHw==", + "version": "7.0.44", + "resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.44.tgz", + "integrity": "sha512-08AuUfWi+KeZI+KC7nU4pU/9tDeAFvE5NSWk+K9nIfuQc6UlOsZtjjeGVYVEn+DEchyXNJ5i10HCn0xRzFXEQA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.1", - "fast-unique-numbers": "^9.0.21", + "@babel/runtime": "^7.27.6", + "fast-unique-numbers": "^9.0.22", "tslib": "^2.8.1" } }, + "node_modules/worker-factory/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/worker-timers": { - "version": "8.0.21", - "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.21.tgz", - "integrity": "sha512-L/QXdrRJQta6FL0STOa+ZwRwl99IboSsBUSPtuRSFIn2gwrDD8tOrjH7rLXGN8VbPFO/9U8vPS5yOX11iwvEdA==", + "version": "8.0.23", + "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.23.tgz", + "integrity": "sha512-1BnWHNNiu5YEutgF7eVZEqNntAsij2oG0r66xDdScoY3fKGFrok2y0xA8OgG6FA+3srrmAplSY6JN5h9jV5D0w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.1", + "@babel/runtime": "^7.27.6", "tslib": "^2.8.1", - "worker-timers-broker": "^8.0.7", - "worker-timers-worker": "^9.0.7" + "worker-timers-broker": "^8.0.9", + "worker-timers-worker": "^9.0.9" } }, "node_modules/worker-timers-broker": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-8.0.7.tgz", - "integrity": "sha512-l89u41E9HnlmVmv9YiU+DrG02jEOMXuyZtNSIhI9gFQjfaY+d3b4pYeLJyu+eTTiF05WA8qkncvce7RY0YWOBQ==", + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-8.0.9.tgz", + "integrity": "sha512-WJsd7aIvu2GBTXp7IBGT1NKnt3ZbiJ2wqb7Pl4nFJXC8pek84+X68TJGVvvrqwHgHPNxSlzpU1nadhcW4PDD7A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.1", - "broker-factory": "^3.1.6", - "fast-unique-numbers": "^9.0.21", + "@babel/runtime": "^7.27.6", + "broker-factory": "^3.1.8", + "fast-unique-numbers": "^9.0.22", "tslib": "^2.8.1", - "worker-timers-worker": "^9.0.7" + "worker-timers-worker": "^9.0.9" } }, + "node_modules/worker-timers-broker/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/worker-timers-worker": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-9.0.7.tgz", - "integrity": "sha512-NyR5XeRTF8SJStwEuDt5BOTVdieqOEIsDVGECV/KVnx3JNbEKXMbh/jtypNwuN2PGKvSNIozYCWu0Yok3lOvQQ==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-9.0.9.tgz", + "integrity": "sha512-OOKTMdHbzx7FaXCW40RS8RxAqLF/R8xU5/YA7CFasDy+jBA5yQWUusSQJUFFTV2Z9ZOpnR+ZWgte/IuAqOAEVw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.1", + "@babel/runtime": "^7.27.6", "tslib": "^2.8.1", - "worker-factory": "^7.0.42" + "worker-factory": "^7.0.44" } }, + "node_modules/worker-timers-worker/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/worker-timers/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/wrap-ansi": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", @@ -10857,6 +13237,28 @@ "dev": true, "license": "ISC" }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "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 + } + } + }, "node_modules/xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", @@ -10882,16 +13284,17 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, - "peer": true + "license": "ISC" }, "node_modules/yargs": { "version": "18.0.0", @@ -10991,6 +13394,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -11007,13 +13411,6 @@ "dependencies": { "tslib": "2.3.0" } - }, - "node_modules/zrender/node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "dev": true, - "license": "0BSD" } } } diff --git a/package.json b/package.json index 47295ef6..a09c473c 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "main": "src-electron/main.js", "scripts": { + "dev": "cross-env PLATFORM=windows webpack serve --config webpack.config.js --mode development", "watch": "cross-env PLATFORM=windows webpack --config webpack.config.js --mode development --watch", "watch-linux": "cross-env PLATFORM=linux webpack --config webpack.config.js --mode development --watch", "localization": "node ./src/localization/localizationHelperCLI.js", @@ -27,50 +28,52 @@ }, "homepage": "https://github.com/vrcx-team/VRCX#readme", "devDependencies": { - "@babel/eslint-parser": "^7.27.5", "@electron/rebuild": "^4.0.1", - "@fontsource/noto-sans-jp": "^5.2.5", - "@fontsource/noto-sans-kr": "^5.2.5", + "@eslint/js": "^9.31.0", + "@fontsource/noto-sans-jp": "^5.2.6", + "@fontsource/noto-sans-kr": "^5.2.6", "@fontsource/noto-sans-sc": "^5.2.6", "@fontsource/noto-sans-tc": "^5.2.6", "@infolektuell/noto-color-emoji": "^0.2.0", "@prettier/plugin-pug": "^3.4.0", + "@types/node": "^24.0.13", "animate.css": "^4.1.1", "copy-webpack-plugin": "^13.0.0", "cross-env": "^7.0.3", "css-loader": "^7.1.2", "dayjs": "^1.11.13", - "default-passive-events": "^4.0.0", "echarts": "^5.6.0", - "electron": "^36.4.0", + "electron": "^37.2.1", "electron-builder": "^26.0.12", "element-ui": "^2.15.14", "esbuild-loader": "^4.3.0", - "eslint": "^9.28.0", + "eslint": "^9.31.0", "eslint-config-prettier": "^10.1.5", - "eslint-plugin-vue": "^9.32.0", + "eslint-plugin-vue": "^9.33.0", + "globals": "^16.3.0", "html-webpack-plugin": "^5.6.3", "mini-css-extract-plugin": "^2.9.2", - "normalize.css": "^8.0.1", "noty": "^3.2.0-beta-deprecated", - "prettier": "^3.5.3", + "pinia": "^2.3.1", + "prettier": "^3.6.2", "pug": "^3.0.3", "pug-plain-loader": "^1.1.0", "raw-loader": "^4.0.2", - "sass": "^1.89.1", + "sass": "^1.89.2", "sass-loader": "^16.0.5", "vue": "^2.7.16", "vue-data-tables": "^3.4.5", "vue-demi": "^0.14.10", "vue-i18n": "^8.28.2", "vue-i18n-bridge": "^9.14.1", - "vue-lazyload": "^1.3.4", + "vue-lazyload": "^1.3.5", "vue-loader": "^15.11.1", "vue-markdown": "^2.2.4", "vue-marquee-text-component": "^1.2.0", - "webpack": "^5.99.9", + "webpack": "^5.100.1", "webpack-cli": "^6.0.1", - "worker-timers": "^8.0.21", + "webpack-dev-server": "^5.2.2", + "worker-timers": "^8.0.23", "yargs": "^18.0.0" }, "build": { @@ -135,6 +138,6 @@ }, "dependencies": { "hazardous": "^0.3.0", - "node-api-dotnet": "^0.9.11" + "node-api-dotnet": "^0.9.12" } } diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 00000000..7b9069ca --- /dev/null +++ b/src/App.vue @@ -0,0 +1,109 @@ + diff --git a/src/api/auth.js b/src/api/auth.js new file mode 100644 index 00000000..262ee1e3 --- /dev/null +++ b/src/api/auth.js @@ -0,0 +1,69 @@ +import { request } from '../service/request'; +import { useUserStore } from '../stores'; + +const loginReq = { + /** + * @param {{ code: string }} params One-time password + * @returns {Promise<{json: any, params}>} + */ + verifyOTP(params) { + return request('auth/twofactorauth/otp/verify', { + method: 'POST', + params + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + + /** + * @param {{ code: string }} params One-time token + * @returns {Promise<{json: any, params}>} + */ + verifyTOTP(params) { + return request('auth/twofactorauth/totp/verify', { + method: 'POST', + params + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + + /** + * @param {{ code: string }} params One-time token + * @returns {Promise<{json: any, params}>} + */ + verifyEmailOTP(params) { + return request('auth/twofactorauth/emailotp/verify', { + method: 'POST', + params + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + + getConfig() { + return request('config', { + method: 'GET' + }).then((json) => { + const args = { + json + }; + useUserStore().handleConfig(args); + return args; + }); + } +}; + +export default loginReq; diff --git a/src/api/avatar.js b/src/api/avatar.js index e43f3b08..9a033b34 100644 --- a/src/api/avatar.js +++ b/src/api/avatar.js @@ -1,19 +1,18 @@ -// #region | API: Avatar +import { request } from '../service/request'; +import { useUserStore } from '../stores'; const avatarReq = { /** - * @param {{ avatarId: string }} params - * @returns {Promise<{json: any, params}>} + * @type {import('../types/avatar').getAvatar} */ getAvatar(params) { - return window.API.call(`avatars/${params.avatarId}`, { + return request(`avatars/${params.avatarId}`, { method: 'GET' }).then((json) => { const args = { json, params }; - window.API.$emit('AVATAR', args); return args; }); }, @@ -37,7 +36,7 @@ const avatarReq = { * @returns {Promise<{json: any, params}>} */ getAvatars(params) { - return window.API.call('avatars', { + return request('avatars', { method: 'GET', params }).then((json) => { @@ -45,16 +44,16 @@ const avatarReq = { json, params }; - window.API.$emit('AVATAR:LIST', args); + return args; }); }, /** - * @param {{ id: string, releaseStatus: 'public' | 'private' }} params + * @param {{ id: string, releaseStatus?: 'public' | 'private', name?: string, description?: string }} params * @returns {Promise<{json: any, params}>} */ saveAvatar(params) { - return window.API.call(`avatars/${params.id}`, { + return request(`avatars/${params.id}`, { method: 'PUT', params }).then((json) => { @@ -62,7 +61,6 @@ const avatarReq = { json, params }; - window.API.$emit('AVATAR:SAVE', args); return args; }); }, @@ -72,7 +70,8 @@ const avatarReq = { * @returns {Promise<{json: any, params}>} */ selectAvatar(params) { - return window.API.call(`avatars/${params.avatarId}/select`, { + const userStore = useUserStore(); + return request(`avatars/${params.avatarId}/select`, { method: 'PUT', params }).then((json) => { @@ -80,7 +79,7 @@ const avatarReq = { json, params }; - window.API.$emit('AVATAR:SELECT', args); + userStore.applyCurrentUser(json); return args; }); }, @@ -90,7 +89,8 @@ const avatarReq = { * @return { Promise<{json: any, params}> } */ selectFallbackAvatar(params) { - return window.API.call(`avatars/${params.avatarId}/selectfallback`, { + const userStore = useUserStore(); + return request(`avatars/${params.avatarId}/selectfallback`, { method: 'PUT', params }).then((json) => { @@ -98,7 +98,7 @@ const avatarReq = { json, params }; - window.API.$emit('AVATAR:SELECT', args); + userStore.applyCurrentUser(json); return args; }); }, @@ -108,14 +108,13 @@ const avatarReq = { * @return { Promise<{json: any, params}> } */ deleteAvatar(params) { - return window.API.call(`avatars/${params.avatarId}`, { + return request(`avatars/${params.avatarId}`, { method: 'DELETE' }).then((json) => { const args = { json, params }; - window.API.$emit('AVATAR:DELETE', args); return args; }); }, @@ -125,14 +124,13 @@ const avatarReq = { * @returns {Promise<{json: any, params}>} */ createImposter(params) { - return window.API.call(`avatars/${params.avatarId}/impostor/enqueue`, { + return request(`avatars/${params.avatarId}/impostor/enqueue`, { method: 'POST' }).then((json) => { const args = { json, params }; - // window.API.$emit('AVATAR:IMPOSTER:CREATE', args); return args; }); }, @@ -142,35 +140,33 @@ const avatarReq = { * @returns {Promise<{json: T, params}>} */ deleteImposter(params) { - return window.API.call(`avatars/${params.avatarId}/impostor`, { + return request(`avatars/${params.avatarId}/impostor`, { method: 'DELETE' }).then((json) => { const args = { json, params }; - // window.API.$emit('AVATAR:IMPOSTER:DELETE', args); return args; }); }, /** - * @returns {Promise<{json: any, params}>} + * @returns {Promise<{json: any}>} */ getAvailableAvatarStyles() { - return window.API.call('avatarStyles', { + return request('avatarStyles', { method: 'GET' }).then((json) => { const args = { json }; - // window.API.$emit('AVATAR:STYLES', args); return args; }); }, /** - * @param {{ avatarId: string }} params + * @param {{ avatarId: string }} avatarId * @returns {Promise<{json: any, params}>} */ getAvatarGallery(avatarId) { @@ -180,7 +176,7 @@ const avatarReq = { n: 100, offset: 0 }; - return window.API.call(`files`, { + return request(`files`, { params, method: 'GET' }).then((json) => { @@ -188,7 +184,6 @@ const avatarReq = { json, params }; - // window.API.$emit('AVATAR:GALLERY', args); return args; }); }, @@ -202,7 +197,7 @@ const avatarReq = { tag: 'avatargallery', galleryId: avatarId }; - return window.API.call('file/image', { + return request('file/image', { uploadImage: true, matchingDimensions: false, postData: JSON.stringify(params), @@ -212,7 +207,6 @@ const avatarReq = { json, params }; - // window.API.$emit('AVATARGALLERYIMAGE:ADD', args); return args; }); }, @@ -225,7 +219,7 @@ const avatarReq = { const params = { ids: order }; - return window.API.call('files/order', { + return request('files/order', { method: 'PUT', params }).then((json) => { @@ -233,11 +227,9 @@ const avatarReq = { json, params }; - // window.API.$emit('AVATARGALLERYIMAGE:ORDER', args); return args; }); } }; -// #endregion export default avatarReq; diff --git a/src/api/avatarModeration.js b/src/api/avatarModeration.js index adf40ce3..5176fc93 100644 --- a/src/api/avatarModeration.js +++ b/src/api/avatarModeration.js @@ -1,14 +1,13 @@ -// #region | API: AvatarModeration +import { request } from '../service/request'; const avatarModerationReq = { getAvatarModerations() { - return window.API.call('auth/user/avatarmoderations', { + return request('auth/user/avatarmoderations', { method: 'GET' }).then((json) => { const args = { json }; - // window.API.$emit('AVATAR-MODERATION:LIST', args); return args; }); }, @@ -18,7 +17,7 @@ const avatarModerationReq = { * @return { Promise<{json: any, params}> } */ sendAvatarModeration(params) { - return window.API.call('auth/user/avatarmoderations', { + return request('auth/user/avatarmoderations', { method: 'POST', params }).then((json) => { @@ -26,7 +25,6 @@ const avatarModerationReq = { json, params }; - // window.API.$emit('AVATAR-MODERATION', args); return args; }); }, @@ -36,7 +34,7 @@ const avatarModerationReq = { * @return { Promise<{json: any, params}> } */ deleteAvatarModeration(params) { - return window.API.call( + return request( `auth/user/avatarmoderations?targetAvatarId=${encodeURIComponent( params.targetAvatarId )}&avatarModerationType=${encodeURIComponent( @@ -50,11 +48,9 @@ const avatarModerationReq = { json, params }; - window.API.$emit('AVATAR-MODERATION:DELETE', args); return args; }); } }; -// #endregion export default avatarModerationReq; diff --git a/src/api/favorite.js b/src/api/favorite.js index cb67a8cc..78ed36e7 100644 --- a/src/api/favorite.js +++ b/src/api/favorite.js @@ -1,29 +1,27 @@ -// #region | API: Favorite +import { request } from '../service/request'; +import { useFavoriteStore, useUserStore } from '../stores'; + +function getCurrentUserId() { + return useUserStore().currentUser.id; +} const favoriteReq = { getFavoriteLimits() { - return window.API.call('auth/user/favoritelimits', { + return request('auth/user/favoritelimits', { method: 'GET' }).then((json) => { const args = { json }; - window.API.$emit('FAVORITE:LIMITS', args); return args; }); }, /** - * @param {{ - * n: number, - * offset: number, - * type: string, - * tag: string - * }} params - * @return { Promise<{json: any, params}> } + * @type {import('../types/favorite').getFavorites} */ getFavorites(params) { - return window.API.call('favorites', { + return request('favorites', { method: 'GET', params }).then((json) => { @@ -31,7 +29,6 @@ const favoriteReq = { json, params }; - window.API.$emit('FAVORITE:LIST', args); return args; }); }, @@ -45,7 +42,7 @@ const favoriteReq = { * @return { Promise<{json: any, params}> } */ addFavorite(params) { - return window.API.call('favorites', { + return request('favorites', { method: 'POST', params }).then((json) => { @@ -53,7 +50,7 @@ const favoriteReq = { json, params }; - window.API.$emit('FAVORITE:ADD', args); + useFavoriteStore().handleFavoriteAdd(args); return args; }); }, @@ -63,14 +60,14 @@ const favoriteReq = { * @return { Promise<{json: any, params}> } */ deleteFavorite(params) { - return window.API.call(`favorites/${params.objectId}`, { + return request(`favorites/${params.objectId}`, { method: 'DELETE' }).then((json) => { const args = { json, params }; - window.API.$emit('FAVORITE:DELETE', args); + useFavoriteStore().handleFavoriteDelete(args); return args; }); }, @@ -80,7 +77,7 @@ const favoriteReq = { * @return { Promise<{json: any, params}> } */ getFavoriteGroups(params) { - return window.API.call('favorite/groups', { + return request('favorite/groups', { method: 'GET', params }).then((json) => { @@ -88,7 +85,6 @@ const favoriteReq = { json, params }; - window.API.$emit('FAVORITE:GROUP:LIST', args); return args; }); }, @@ -99,8 +95,8 @@ const favoriteReq = { * @return { Promise<{json: any, params}> } */ saveFavoriteGroup(params) { - return window.API.call( - `favorite/group/${params.type}/${params.group}/${window.API.currentUser.id}`, + return request( + `favorite/group/${params.type}/${params.group}/${getCurrentUserId()}`, { method: 'PUT', params @@ -110,7 +106,6 @@ const favoriteReq = { json, params }; - window.API.$emit('FAVORITE:GROUP:SAVE', args); return args; }); }, @@ -123,8 +118,8 @@ const favoriteReq = { * @return { Promise<{json: any, params}> } */ clearFavoriteGroup(params) { - return window.API.call( - `favorite/group/${params.type}/${params.group}/${window.API.currentUser.id}`, + return request( + `favorite/group/${params.type}/${params.group}/${getCurrentUserId()}`, { method: 'DELETE', params @@ -134,20 +129,16 @@ const favoriteReq = { json, params }; - window.API.$emit('FAVORITE:GROUP:CLEAR', args); + useFavoriteStore().handleFavoriteGroupClear(args); return args; }); }, /** - * @param {{ - * n: number, - * offset: number - * }} params - * @return { Promise<{json: any, params}> } + * @type {import('../types/favorite').getFavoriteWorlds} */ getFavoriteWorlds(params) { - return window.API.call('worlds/favorites', { + return request('worlds/favorites', { method: 'GET', params }).then((json) => { @@ -155,20 +146,15 @@ const favoriteReq = { json, params }; - window.API.$emit('FAVORITE:WORLD:LIST', args); return args; }); }, /** - * @param {{ - * n: number, - * offset: number - * }} params - * @return { Promise<{json: any, params}> } + * @type {import('../types/favorite').getFavoriteAvatars} */ getFavoriteAvatars(params) { - return window.API.call('avatars/favorites', { + return request('avatars/favorites', { method: 'GET', params }).then((json) => { @@ -176,12 +162,9 @@ const favoriteReq = { json, params }; - window.API.$emit('FAVORITE:AVATAR:LIST', args); return args; }); } }; -// #endregion - export default favoriteReq; diff --git a/src/api/friend.js b/src/api/friend.js index ebfc3559..5af61b16 100644 --- a/src/api/friend.js +++ b/src/api/friend.js @@ -1,13 +1,14 @@ -// #region | API: Friend +import { request } from '../service/request'; +import { useUserStore } from '../stores/user'; const friendReq = { /** * Fetch friends of current user. - * @param {{ n: number, offset: number, offline: boolean }} params - * @returns {Promise<{json: any, params}>} + * @type {import('../types/friend').getFriends} */ getFriends(params) { - return window.API.call('auth/user/friends', { + const userStore = useUserStore(); + return request('auth/user/friends', { method: 'GET', params }).then((json) => { @@ -15,7 +16,13 @@ const friendReq = { json, params }; - window.API.$emit('FRIEND:LIST', args); + for (const user of args.json) { + if (!user.displayName) { + console.error('/friends gave us garbage', user); + continue; + } + userStore.applyUser(user); + } return args; }); }, @@ -25,14 +32,13 @@ const friendReq = { * @returns {Promise<{json: T, params}>} */ sendFriendRequest(params) { - return window.API.call(`user/${params.userId}/friendRequest`, { + return request(`user/${params.userId}/friendRequest`, { method: 'POST' }).then((json) => { const args = { json, params }; - window.API.$emit('FRIEND:REQUEST', args); return args; }); }, @@ -42,14 +48,13 @@ const friendReq = { * @returns {Promise<{json: any, params}>} */ cancelFriendRequest(params) { - return window.API.call(`user/${params.userId}/friendRequest`, { + return request(`user/${params.userId}/friendRequest`, { method: 'DELETE' }).then((json) => { const args = { json, params }; - // window.API.$emit('FRIEND:REQUEST:CANCEL', args); return args; }); }, @@ -59,14 +64,13 @@ const friendReq = { * @returns {Promise<{json: any, params}>} */ deleteFriend(params) { - return window.API.call(`auth/user/friends/${params.userId}`, { + return request(`auth/user/friends/${params.userId}`, { method: 'DELETE' }).then((json) => { const args = { json, params }; - window.API.$emit('FRIEND:DELETE', args); return args; }); }, @@ -76,7 +80,7 @@ const friendReq = { * @returns {Promise<{json: any, params}>} */ getFriendStatus(params) { - return window.API.call(`user/${params.userId}/friendStatus`, { + return request(`user/${params.userId}/friendStatus`, { method: 'GET' }).then((json) => { console.log('getFriendStatus', json); @@ -84,15 +88,12 @@ const friendReq = { json, params }; - window.API.$emit('FRIEND:STATUS', args); return args; }); }, - // ------------------- need to test ------------------- - deleteHiddenFriendRequest(params, userId) { - return window.API.call(`user/${userId}/friendRequest`, { + return request(`user/${userId}/friendRequest`, { method: 'DELETE', params }).then((json) => { @@ -101,11 +102,9 @@ const friendReq = { params, userId }; - window.API.$emit('NOTIFICATION:HIDE', args); return args; }); } }; -// #endregion export default friendReq; diff --git a/src/api/group.js b/src/api/group.js index b26397ad..e9d4969a 100644 --- a/src/api/group.js +++ b/src/api/group.js @@ -1,3 +1,9 @@ +import { request } from '../service/request'; +import { useUserStore, useGroupStore } from '../stores'; + +function getCurrentUserId() { + return useUserStore().currentUser.id; +} const groupReq = { /** * @param {string} groupId @@ -5,7 +11,7 @@ const groupReq = { * @returns */ setGroupRepresentation(groupId, params) { - return window.API.call(`groups/${groupId}/representation`, { + return request(`groups/${groupId}/representation`, { method: 'PUT', params }).then((json) => { @@ -23,7 +29,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ cancelGroupRequest(params) { - return window.API.call(`groups/${params.groupId}/requests`, { + return request(`groups/${params.groupId}/requests`, { method: 'DELETE' }).then((json) => { const args = { @@ -39,12 +45,9 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ deleteGroupPost(params) { - return window.API.call( - `groups/${params.groupId}/posts/${params.postId}`, - { - method: 'DELETE' - } - ).then((json) => { + return request(`groups/${params.groupId}/posts/${params.postId}`, { + method: 'DELETE' + }).then((json) => { const args = { json, params @@ -53,10 +56,10 @@ const groupReq = { }); }, /** - * @param {{ groupId: string }} params + * @type {import('../types/group').getGroup} */ getGroup(params) { - return window.API.call(`groups/${params.groupId}`, { + return request(`groups/${params.groupId}`, { method: 'GET', params: { includeRoles: params.includeRoles || false @@ -66,23 +69,48 @@ const groupReq = { json, params }; - window.API.$emit('GROUP', args); return args; }); }, + /** + * + * @param {{ groupId: string }} params + * @return { Promise<{json: any, params}> } + */ + getCachedGroup(params) { + const groupStore = useGroupStore(); + return new Promise((resolve, reject) => { + const ref = groupStore.cachedGroups.get(params.groupId); + if (typeof ref === 'undefined') { + groupReq + .getGroup(params) + .catch(reject) + .then((args) => { + args.ref = groupStore.applyGroup(args.json); + resolve(args); + }); + } else { + resolve({ + cache: true, + json: ref, + params, + ref + }); + } + }); + }, /** * @param {{ userId: string }} params * @return { Promise<{json: any, params}> } */ getRepresentedGroup(params) { - return window.API.call(`users/${params.userId}/groups/represented`, { + return request(`users/${params.userId}/groups/represented`, { method: 'GET' }).then((json) => { const args = { json, params }; - window.API.$emit('GROUP:REPRESENTED', args); return args; }); }, @@ -91,14 +119,13 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ getGroups(params) { - return window.API.call(`users/${params.userId}/groups`, { + return request(`users/${params.userId}/groups`, { method: 'GET' }).then((json) => { const args = { json, params }; - window.API.$emit('GROUP:LIST', args); return args; }); }, @@ -107,14 +134,13 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ joinGroup(params) { - return window.API.call(`groups/${params.groupId}/join`, { + return request(`groups/${params.groupId}/join`, { method: 'POST' }).then((json) => { const args = { json, params }; - window.API.$emit('GROUP:JOIN', args); return args; }); }, @@ -123,7 +149,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ leaveGroup(params) { - return window.API.call(`groups/${params.groupId}/leave`, { + return request(`groups/${params.groupId}/leave`, { method: 'POST' }).then((json) => { const args = { @@ -138,7 +164,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ groupStrictsearch(params) { - return window.API.call(`groups/strictsearch`, { + return request(`groups/strictsearch`, { method: 'GET', params }).then((json) => { @@ -159,7 +185,7 @@ const groupReq = { } */ setGroupMemberProps(userId, groupId, params) { - return window.API.call(`groups/${groupId}/members/${userId}`, { + return request(`groups/${groupId}/members/${userId}`, { method: 'PUT', params }).then((json) => { @@ -169,7 +195,6 @@ const groupReq = { groupId, params }; - window.API.$emit('GROUP:MEMBER:PROPS', args); return args; }); }, @@ -182,7 +207,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ addGroupMemberRole(params) { - return window.API.call( + return request( `groups/${params.groupId}/members/${params.userId}/roles/${params.roleId}`, { method: 'PUT' @@ -192,7 +217,6 @@ const groupReq = { json, params }; - // window.API.$emit('GROUP:MEMBER:ROLE:CHANGE', args); return args; }); }, @@ -205,7 +229,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ removeGroupMemberRole(params) { - return window.API.call( + return request( `groups/${params.groupId}/members/${params.userId}/roles/${params.roleId}`, { method: 'DELETE' @@ -215,19 +239,17 @@ const groupReq = { json, params }; - // window.API.$emit('GROUP:MEMBER:ROLE:CHANGE', args); return args; }); }, getGroupPermissions(params) { - return window.API.call(`users/${params.userId}/groups/permissions`, { + return request(`users/${params.userId}/groups/permissions`, { method: 'GET' }).then((json) => { const args = { json, params }; - window.API.$emit('GROUP:PERMISSIONS', args); return args; }); }, @@ -240,7 +262,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ getGroupPosts(params) { - return window.API.call(`groups/${params.groupId}/posts`, { + return request(`groups/${params.groupId}/posts`, { method: 'GET', params }).then((json) => { @@ -248,28 +270,23 @@ const groupReq = { json, params }; - window.API.$emit('GROUP:POSTS', args); return args; }); }, editGroupPost(params) { - return window.API.call( - `groups/${params.groupId}/posts/${params.postId}`, - { - method: 'PUT', - params - } - ).then((json) => { + return request(`groups/${params.groupId}/posts/${params.postId}`, { + method: 'PUT', + params + }).then((json) => { const args = { json, params }; - window.API.$emit('GROUP:POST', args); return args; }); }, createGroupPost(params) { - return window.API.call(`groups/${params.groupId}/posts`, { + return request(`groups/${params.groupId}/posts`, { method: 'POST', params }).then((json) => { @@ -277,7 +294,6 @@ const groupReq = { json, params }; - window.API.$emit('GROUP:POST', args); return args; }); }, @@ -289,17 +305,13 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ getGroupMember(params) { - return window.API.call( - `groups/${params.groupId}/members/${params.userId}`, - { - method: 'GET' - } - ).then((json) => { + return request(`groups/${params.groupId}/members/${params.userId}`, { + method: 'GET' + }).then((json) => { const args = { json, params }; - // window.API.$emit('GROUP:MEMBER', args); return args; }); }, @@ -312,7 +324,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ getGroupMembers(params) { - return window.API.call(`groups/${params.groupId}/members`, { + return request(`groups/${params.groupId}/members`, { method: 'GET', params }).then((json) => { @@ -320,7 +332,6 @@ const groupReq = { json, params }; - window.API.$emit('GROUP:MEMBERS', args); return args; }); }, @@ -334,7 +345,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ getGroupMembersSearch(params) { - return window.API.call(`groups/${params.groupId}/members/search`, { + return request(`groups/${params.groupId}/members/search`, { method: 'GET', params }).then((json) => { @@ -352,7 +363,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ blockGroup(params) { - return window.API.call(`groups/${params.groupId}/block`, { + return request(`groups/${params.groupId}/block`, { method: 'POST' }).then((json) => { const args = { @@ -370,12 +381,9 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ unblockGroup(params) { - return window.API.call( - `groups/${params.groupId}/members/${params.userId}`, - { - method: 'DELETE' - } - ).then((json) => { + return request(`groups/${params.groupId}/members/${params.userId}`, { + method: 'DELETE' + }).then((json) => { const args = { json, params @@ -391,7 +399,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ sendGroupInvite(params) { - return window.API.call(`groups/${params.groupId}/invites`, { + return request(`groups/${params.groupId}/invites`, { method: 'POST', params: { userId: params.userId @@ -401,7 +409,6 @@ const groupReq = { json, params }; - window.API.$emit('GROUP:INVITE', args); return args; }); }, @@ -413,18 +420,13 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ kickGroupMember(params) { - return window.API.call( - `groups/${params.groupId}/members/${params.userId}`, - { - method: 'DELETE' - } - ).then((json) => { + return request(`groups/${params.groupId}/members/${params.userId}`, { + method: 'DELETE' + }).then((json) => { const args = { json, params }; - // useless code - // window.API.$emit('GROUP:MEMBER:KICK', args); return args; }); }, @@ -433,7 +435,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ banGroupMember(params) { - return window.API.call(`groups/${params.groupId}/bans`, { + return request(`groups/${params.groupId}/bans`, { method: 'POST', params: { userId: params.userId @@ -443,24 +445,17 @@ const groupReq = { json, params }; - // useless code - // window.API.$emit('GROUP:MEMBER:BAN', args); return args; }); }, unbanGroupMember(params) { - return window.API.call( - `groups/${params.groupId}/bans/${params.userId}`, - { - method: 'DELETE' - } - ).then((json) => { + return request(`groups/${params.groupId}/bans/${params.userId}`, { + method: 'DELETE' + }).then((json) => { const args = { json, params }; - // useless code - // window.API.$emit('GROUP:MEMBER:UNBAN', args); return args; }); }, @@ -469,97 +464,73 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ deleteSentGroupInvite(params) { - return window.API.call( - `groups/${params.groupId}/invites/${params.userId}`, - { - method: 'DELETE' - } - ).then((json) => { + return request(`groups/${params.groupId}/invites/${params.userId}`, { + method: 'DELETE' + }).then((json) => { const args = { json, params }; - // useless code - // window.API.$emit('GROUP:INVITE:DELETE', args); return args; }); }, deleteBlockedGroupRequest(params) { - return window.API.call( - `groups/${params.groupId}/members/${params.userId}`, - { - method: 'DELETE' - } - ).then((json) => { + return request(`groups/${params.groupId}/members/${params.userId}`, { + method: 'DELETE' + }).then((json) => { const args = { json, params }; - // useless code - // window.API.$emit('GROUP:BLOCKED:DELETE', args); return args; }); }, acceptGroupInviteRequest(params) { - return window.API.call( - `groups/${params.groupId}/requests/${params.userId}`, - { - method: 'PUT', - params: { - action: 'accept' - } + return request(`groups/${params.groupId}/requests/${params.userId}`, { + method: 'PUT', + params: { + action: 'accept' } - ).then((json) => { + }).then((json) => { const args = { json, params }; - // useless code - // window.API.$emit('GROUP:INVITE:ACCEPT', args); return args; }); }, rejectGroupInviteRequest(params) { - return window.API.call( - `groups/${params.groupId}/requests/${params.userId}`, - { - method: 'PUT', - params: { - action: 'reject' - } + return request(`groups/${params.groupId}/requests/${params.userId}`, { + method: 'PUT', + params: { + action: 'reject' } - ).then((json) => { + }).then((json) => { const args = { json, params }; - // useless code - // window.API.$emit('GROUP:INVITE:REJECT', args); + return args; }); }, blockGroupInviteRequest(params) { - return window.API.call( - `groups/${params.groupId}/requests/${params.userId}`, - { - method: 'PUT', - params: { - action: 'reject', - block: true - } + return request(`groups/${params.groupId}/requests/${params.userId}`, { + method: 'PUT', + params: { + action: 'reject', + block: true } - ).then((json) => { + }).then((json) => { const args = { json, params }; - // useless code - // window.API.$emit('GROUP:INVITE:BLOCK', args); return args; }); }, getGroupBans(params) { - return window.API.call(`groups/${params.groupId}/bans`, { + return request(`groups/${params.groupId}/bans`, { method: 'GET', params }).then((json) => { @@ -575,7 +546,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ getGroupAuditLogTypes(params) { - return window.API.call(`groups/${params.groupId}/auditLogTypes`, { + return request(`groups/${params.groupId}/auditLogTypes`, { method: 'GET' }).then((json) => { const args = { @@ -590,7 +561,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ getGroupLogs(params) { - return window.API.call(`groups/${params.groupId}/auditLogs`, { + return request(`groups/${params.groupId}/auditLogs`, { method: 'GET', params }).then((json) => { @@ -606,7 +577,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ getGroupInvites(params) { - return window.API.call(`groups/${params.groupId}/invites`, { + return request(`groups/${params.groupId}/invites`, { method: 'GET', params }).then((json) => { @@ -622,7 +593,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ getGroupJoinRequests(params) { - return window.API.call(`groups/${params.groupId}/requests`, { + return request(`groups/${params.groupId}/requests`, { method: 'GET', params }).then((json) => { @@ -630,7 +601,6 @@ const groupReq = { json, params }; - // window.API.$emit('GROUP:JOINREQUESTS', args); return args; }); }, @@ -639,8 +609,8 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ getGroupInstances(params) { - return window.API.call( - `users/${window.API.currentUser.id}/instances/groups/${params.groupId}`, + return request( + `users/${getCurrentUserId()}/instances/groups/${params.groupId}`, { method: 'GET' } @@ -657,7 +627,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ getGroupRoles(params) { - return window.API.call(`groups/${params.groupId}/roles`, { + return request(`groups/${params.groupId}/roles`, { method: 'GET', params }).then((json) => { @@ -665,22 +635,16 @@ const groupReq = { json, params }; - // useless code - // this.$emit('GROUP:ROLES', args); return args; }); }, getUsersGroupInstances() { - return window.API.call( - `users/${window.API.currentUser.id}/instances/groups`, - { - method: 'GET' - } - ).then((json) => { + return request(`users/${getCurrentUserId()}/instances/groups`, { + method: 'GET' + }).then((json) => { const args = { json }; - window.API.$emit('GROUP:USER:INSTANCES', args); return args; }); }, @@ -696,7 +660,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ groupSearch(params) { - return window.API.call(`groups`, { + return request(`groups`, { method: 'GET', params }).then((json) => { @@ -717,7 +681,7 @@ const groupReq = { * @return { Promise<{json: any, params}> } */ getGroupGallery(params) { - return window.API.call( + return request( `groups/${params.groupId}/galleries/${params.galleryId}`, { method: 'GET', @@ -735,10 +699,9 @@ const groupReq = { }); } - // no place to use this // getRequestedGroups() { - // return window.API.call( - // `users/${window.API.currentUser.id}/groups/requested`, + // return request( + // `users/${API.currentUser.id}/groups/requested`, // { // method: 'GET' // } @@ -746,18 +709,17 @@ const groupReq = { // const args = { // json // }; - // window.API.$emit('GROUP:REQUESTED', args); + // API.$emit('GROUP:REQUESTED', args); // return args; // }); // } - // ----------------- left over code ----------------- // /** // * @param {{ groupId: string }} params // * @return { Promise<{json: any, params}> } // */ // API.getGroupAnnouncement = function (params) { - // return this.call(`groups/${params.groupId}/announcement`, { + // return request(`groups/${params.groupId}/announcement`, { // method: 'GET' // }).then((json) => { // var args = { diff --git a/src/api/image.js b/src/api/image.js index 7aff5915..067b2200 100644 --- a/src/api/image.js +++ b/src/api/image.js @@ -1,25 +1,26 @@ +import { request } from '../service/request'; +import { useAvatarStore, useWorldStore } from '../stores'; + const imageReq = { - // use in uploadAvatarImage - // need to test async uploadAvatarFailCleanup(id) { - const json = await window.API.call(`file/${id}`, { + const avatarStore = useAvatarStore(); + const json = await request(`file/${id}`, { method: 'GET' }); const fileId = json.id; const fileVersion = json.versions[json.versions.length - 1].version; - window.API.call(`file/${fileId}/${fileVersion}/signature/finish`, { + request(`file/${fileId}/${fileVersion}/signature/finish`, { method: 'PUT' }); - window.API.call(`file/${fileId}/${fileVersion}/file/finish`, { + request(`file/${fileId}/${fileVersion}/file/finish`, { method: 'PUT' }); - window.$app.avatarDialog.loading = false; - // window.$app.changeAvatarImageDialogLoading = false; + avatarStore.avatarDialog.loading = false; }, async uploadAvatarImage(params, fileId) { try { - return await window.API.call(`file/${fileId}`, { + return await request(`file/${fileId}`, { method: 'POST', params }).then((json) => { @@ -28,7 +29,6 @@ const imageReq = { params, fileId }; - // window.API.$emit('AVATARIMAGE:INIT', args); return args; }); } catch (err) { @@ -36,12 +36,11 @@ const imageReq = { imageReq.uploadAvatarFailCleanup(fileId); throw err; } - // return void 0; }, async uploadAvatarImageFileStart(params) { try { - return await window.API.call( + return await request( `file/${params.fileId}/${params.fileVersion}/file/start`, { method: 'PUT' @@ -51,18 +50,16 @@ const imageReq = { json, params }; - // window.API.$emit('AVATARIMAGE:FILESTART', args); return args; }); } catch (err) { console.error(err); imageReq.uploadAvatarFailCleanup(params.fileId); } - return void 0; }, uploadAvatarImageFileFinish(params) { - return window.API.call( + return request( `file/${params.fileId}/${params.fileVersion}/file/finish`, { method: 'PUT', @@ -76,14 +73,13 @@ const imageReq = { json, params }; - // window.API.$emit('AVATARIMAGE:FILEFINISH', args); return args; }); }, async uploadAvatarImageSigStart(params) { try { - return await window.API.call( + return await request( `file/${params.fileId}/${params.fileVersion}/signature/start`, { method: 'PUT' @@ -93,18 +89,16 @@ const imageReq = { json, params }; - // window.API.$emit('AVATARIMAGE:SIGSTART', args); return args; }); } catch (err) { console.error(err); imageReq.uploadAvatarFailCleanup(params.fileId); } - return void 0; }, uploadAvatarImageSigFinish(params) { - return window.API.call( + return request( `file/${params.fileId}/${params.fileVersion}/signature/finish`, { method: 'PUT', @@ -118,13 +112,12 @@ const imageReq = { json, params }; - // window.API.$emit('AVATARIMAGE:SIGFINISH', args); return args; }); }, setAvatarImage(params) { - return window.API.call(`avatars/${params.id}`, { + return request(`avatars/${params.id}`, { method: 'PUT', params }).then((json) => { @@ -132,33 +125,29 @@ const imageReq = { json, params }; - // window.API.$emit('AVATARIMAGE:SET', args); - window.API.$emit('AVATAR', args); return args; }); }, - // use in uploadWorldImage - // need to test async uploadWorldFailCleanup(id) { - const json = await window.API.call(`file/${id}`, { + const worldStore = useWorldStore(); + const json = await request(`file/${id}`, { method: 'GET' }); const fileId = json.id; const fileVersion = json.versions[json.versions.length - 1].version; - window.API.call(`file/${fileId}/${fileVersion}/signature/finish`, { + request(`file/${fileId}/${fileVersion}/signature/finish`, { method: 'PUT' }); - window.API.call(`file/${fileId}/${fileVersion}/file/finish`, { + request(`file/${fileId}/${fileVersion}/file/finish`, { method: 'PUT' }); - window.$app.worldDialog.loading = false; - // window.$app.changeWorldImageDialogLoading = false; + worldStore.worldDialog.loading = false; }, async uploadWorldImage(params, fileId) { try { - return await window.API.call(`file/${fileId}`, { + return await request(`file/${fileId}`, { method: 'POST', params }).then((json) => { @@ -167,7 +156,6 @@ const imageReq = { params, fileId }; - // window.API.$emit('WORLDIMAGE:INIT', args); return args; }); } catch (err) { @@ -179,7 +167,7 @@ const imageReq = { async uploadWorldImageFileStart(params) { try { - return await window.API.call( + return await request( `file/${params.fileId}/${params.fileVersion}/file/start`, { method: 'PUT' @@ -189,7 +177,6 @@ const imageReq = { json, params }; - // window.API.$emit('WORLDIMAGE:FILESTART', args); return args; }); } catch (err) { @@ -200,7 +187,7 @@ const imageReq = { }, uploadWorldImageFileFinish(params) { - return window.API.call( + return request( `file/${params.fileId}/${params.fileVersion}/file/finish`, { method: 'PUT', @@ -214,14 +201,13 @@ const imageReq = { json, params }; - // window.API.$emit('WORLDIMAGE:FILEFINISH', args); return args; }); }, async uploadWorldImageSigStart(params) { try { - return await window.API.call( + return await request( `file/${params.fileId}/${params.fileVersion}/signature/start`, { method: 'PUT' @@ -231,7 +217,6 @@ const imageReq = { json, params }; - // window.API.$emit('WORLDIMAGE:SIGSTART', args); return args; }); } catch (err) { @@ -242,7 +227,7 @@ const imageReq = { }, uploadWorldImageSigFinish(params) { - return window.API.call( + return request( `file/${params.fileId}/${params.fileVersion}/signature/finish`, { method: 'PUT', @@ -256,13 +241,13 @@ const imageReq = { json, params }; - // window.API.$emit('WORLDIMAGE:SIGFINISH', args); return args; }); }, setWorldImage(params) { - return window.API.call(`worlds/${params.id}`, { + const worldStore = useWorldStore(); + return request(`worlds/${params.id}`, { method: 'PUT', params }).then((json) => { @@ -270,27 +255,25 @@ const imageReq = { json, params }; - // window.API.$emit('WORLDIMAGE:SET', args); - window.API.$emit('WORLD', args); + args.ref = worldStore.applyWorld(json); return args; }); }, getAvatarImages(params) { - return window.API.call(`file/${params.fileId}`, { + return request(`file/${params.fileId}`, { method: 'GET' }).then((json) => { const args = { json, params }; - // window.API.$emit('AVATARIMAGE:GET', args); return args; }); }, getWorldImages(params) { - return window.API.call(`file/${params.fileId}`, { + return request(`file/${params.fileId}`, { method: 'GET', params }).then((json) => { @@ -298,7 +281,6 @@ const imageReq = { json, params }; - // window.API.$emit('WORLDIMAGE:GET', args); return args; }); } diff --git a/src/api/index.js b/src/api/index.js index 0da1da03..65646f57 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -1,9 +1,6 @@ /** * API requests * Export all API requests from here - * - * "window.API" is used as app.js is a large IIFE, preventing direct API export. No current issues - * Refactoring may be required */ import userRequest from './user'; @@ -21,6 +18,7 @@ import inviteMessagesRequest from './inviteMessages'; import imageRequest from './image'; import miscRequest from './misc'; import groupRequest from './group'; +import authRequest from './auth'; import inventoryRequest from './inventory'; import propRequest from './prop'; @@ -39,6 +37,7 @@ window.request = { inviteMessagesRequest, imageRequest, miscRequest, + authRequest, groupRequest, inventoryRequest, propRequest @@ -59,6 +58,7 @@ export { inviteMessagesRequest, imageRequest, miscRequest, + authRequest, groupRequest, inventoryRequest, propRequest diff --git a/src/api/instance.js b/src/api/instance.js index 08bce4d9..5deb5aa2 100644 --- a/src/api/instance.js +++ b/src/api/instance.js @@ -1,22 +1,22 @@ -// #region | API: Instance +import { $app } from '../app'; +import { t } from '../plugin'; +import { request } from '../service/request'; +import { useInstanceStore } from '../stores'; const instanceReq = { /** - * @param {{worldId: string, instanceId: string}} params - * @returns {Promise<{json: any, params}>} + * @type {import('../types/instance').getInstance} */ getInstance(params) { - return window.API.call( - `instances/${params.worldId}:${params.instanceId}`, - { - method: 'GET' - } - ).then((json) => { + const instanceStore = useInstanceStore(); + return request(`instances/${params.worldId}:${params.instanceId}`, { + method: 'GET' + }).then((json) => { const args = { json, params }; - window.API.$emit('INSTANCE', args); + args.ref = instanceStore.applyInstance(json); return args; }); }, @@ -37,7 +37,8 @@ const instanceReq = { * @returns {Promise<{json: any, params}>} */ createInstance(params) { - return window.API.call('instances', { + const instanceStore = useInstanceStore(); + return request('instances', { method: 'POST', params }).then((json) => { @@ -45,7 +46,7 @@ const instanceReq = { json, params }; - window.API.$emit('INSTANCE', args); + args.ref = instanceStore.applyInstance(json); return args; }); }, @@ -59,7 +60,7 @@ const instanceReq = { if (instance.shortName) { params.shortName = instance.shortName; } - return window.API.call( + return request( `instances/${instance.worldId}:${instance.instanceId}/shortName`, { method: 'GET', @@ -80,14 +81,15 @@ const instanceReq = { * @returns {Promise<{json: any, params}>} */ getInstanceFromShortName(params) { - return window.API.call(`instances/s/${params.shortName}`, { + const instanceStore = useInstanceStore(); + return request(`instances/s/${params.shortName}`, { method: 'GET' }).then((json) => { const args = { json, params }; - window.API.$emit('INSTANCE', args); + args.ref = instanceStore.applyInstance(json); return args; }); }, @@ -105,7 +107,7 @@ const instanceReq = { if (instance.shortName) { params.shortName = instance.shortName; } - return window.API.call( + return request( `invite/myself/to/${instance.worldId}:${instance.instanceId}`, { method: 'POST', @@ -121,20 +123,19 @@ const instanceReq = { }) .catch((err) => { if (err?.error?.message) { - window.$app.$message({ + $app.$message({ message: err.error.message, type: 'error' }); throw err; } - window.$app.$message({ - message: window.$t('message.instance.not_allowed'), + $app.$message({ + message: t('message.instance.not_allowed'), type: 'error' }); throw err; }); } }; -// #endregion export default instanceReq; diff --git a/src/api/inventory.js b/src/api/inventory.js index 8760ecdc..b9fcc560 100644 --- a/src/api/inventory.js +++ b/src/api/inventory.js @@ -1,10 +1,12 @@ +import { request } from '../service/request'; + const inventoryReq = { /** * @param {{ inventoryId: string, userId: string }} params * @returns {Promise<{json: any, params}>} */ getUserInventoryItem(params) { - return window.API.call( + return request( `user/${params.userId}/inventory/${params.inventoryId}`, { method: 'GET' @@ -23,7 +25,7 @@ const inventoryReq = { * @returns {Promise<{json: any, params}>} */ getInventoryItem(params) { - return window.API.call(`inventory/${params.inventoryId}`, { + return request(`inventory/${params.inventoryId}`, { method: 'GET', params }).then((json) => { @@ -40,7 +42,7 @@ const inventoryReq = { * @returns {Promise<{json: any, params}>} */ getInventoryItems(params) { - return window.API.call('inventory', { + return request('inventory', { method: 'GET', params }).then((json) => { @@ -57,7 +59,7 @@ const inventoryReq = { * @returns {Promise<{json: any, params}>} */ consumeInventoryBundle(params) { - return window.API.call(`inventory/${params.inventoryId}/consume`, { + return request(`inventory/${params.inventoryId}/consume`, { method: 'PUT', params }).then((json) => { @@ -74,13 +76,10 @@ const inventoryReq = { * @returns {Promise<{json: any, params}>} */ getInventoryTemplate(params) { - return window.API.call( - `inventory/template/${params.inventoryTemplateId}`, - { - method: 'GET', - params - } - ).then((json) => { + return request(`inventory/template/${params.inventoryTemplateId}`, { + method: 'GET', + params + }).then((json) => { const args = { json, params diff --git a/src/api/inviteMessages.js b/src/api/inviteMessages.js index d6522349..e3450c56 100644 --- a/src/api/inviteMessages.js +++ b/src/api/inviteMessages.js @@ -1,30 +1,28 @@ -// #region | App: Invite Messages +import { request } from '../service/request'; +import { useUserStore } from '../stores'; + +function getCurrentUserId() { + return useUserStore().currentUser.id; +} const inviteMessagesReq = { refreshInviteMessageTableData(messageType) { - return window.API.call( - `message/${window.API.currentUser.id}/${messageType}`, - { - method: 'GET' - } - ).then((json) => { + return request(`message/${getCurrentUserId()}/${messageType}`, { + method: 'GET' + }).then((json) => { const args = { json, messageType }; - window.API.$emit(`INVITE:${messageType.toUpperCase()}`, args); return args; }); }, editInviteMessage(params, messageType, slot) { - return window.API.call( - `message/${window.API.currentUser.id}/${messageType}/${slot}`, - { - method: 'PUT', - params - } - ).then((json) => { + return request(`message/${getCurrentUserId()}/${messageType}/${slot}`, { + method: 'PUT', + params + }).then((json) => { const args = { json, params, @@ -36,6 +34,4 @@ const inviteMessagesReq = { } }; -// #endregion - export default inviteMessagesReq; diff --git a/src/api/misc.js b/src/api/misc.js index 6598b7b6..8d3b900c 100644 --- a/src/api/misc.js +++ b/src/api/misc.js @@ -1,6 +1,13 @@ +import { request } from '../service/request'; +import { useUserStore } from '../stores'; + +function getCurrentUserId() { + return useUserStore().currentUser.id; +} + const miscReq = { getBundles(fileId) { - return window.API.call(`file/${fileId}`, { + return request(`file/${fileId}`, { method: 'GET' }).then((json) => { const args = { @@ -11,7 +18,7 @@ const miscReq = { }, saveNote(params) { - return window.API.call('userNotes', { + return request('userNotes', { method: 'POST', params }).then((json) => { @@ -19,7 +26,6 @@ const miscReq = { json, params }; - // window.API.$emit('NOTE', args); return args; }); }, @@ -34,7 +40,7 @@ const miscReq = { * @return { Promise<{json: any, params}> } */ reportUser(params) { - return window.API.call(`feedback/${params.userId}/user`, { + return request(`feedback/${params.userId}/user`, { method: 'POST', params: { contentType: params.contentType, @@ -46,7 +52,6 @@ const miscReq = { json, params }; - // window.API.$emit('FEEDBACK:REPORT:USER', args); return args; }); }, @@ -59,7 +64,7 @@ const miscReq = { * @return { Promise<{json: any, params}> } */ getFileAnalysis(params) { - return window.API.call( + return request( `analysis/${params.fileId}/${params.version}/${params.variant}`, { method: 'GET' @@ -69,19 +74,17 @@ const miscReq = { json, params }; - // window.API.$emit('FILE:ANALYSIS', args); return args; }); }, getVRChatCredits() { - return window.API.call(`user/${window.API.currentUser.id}/balance`, { + return request(`user/${getCurrentUserId()}/balance`, { method: 'GET' }).then((json) => { const args = { json }; - // window.API.$emit('VRCCREDITS', args); return args; }); }, @@ -94,7 +97,7 @@ const miscReq = { * @returns {Promise<{json: any, params}>} */ closeInstance(params) { - return window.API.call(`instances/${params.location}`, { + return request(`instances/${params.location}`, { method: 'DELETE', params: { hardClose: params.hardClose ?? false @@ -104,7 +107,6 @@ const miscReq = { json, params }; - window.API.$emit('INSTANCE:CLOSE', args); return args; }); }, @@ -116,8 +118,8 @@ const miscReq = { * @returns {Promise<{json: any, params}>} */ deleteWorldPersistData(params) { - return window.API.call( - `users/${window.API.currentUser.id}/${params.worldId}/persist`, + return request( + `users/${getCurrentUserId()}/${params.worldId}/persist`, { method: 'DELETE' } @@ -126,7 +128,6 @@ const miscReq = { json, params }; - window.API.$emit('WORLD:PERSIST:DELETE', args); return args; }); }, @@ -138,8 +139,8 @@ const miscReq = { * @returns {Promise<{json: any, params}>} */ hasWorldPersistData(params) { - return window.API.call( - `users/${window.API.currentUser.id}/${params.worldId}/persist/exists`, + return request( + `users/${getCurrentUserId()}/${params.worldId}/persist/exists`, { method: 'GET' } @@ -148,47 +149,41 @@ const miscReq = { json, params }; - window.API.$emit('WORLD:PERSIST:HAS', args); return args; }); }, updateBadge(params) { - return window.API.call( - `users/${window.API.currentUser.id}/badges/${params.badgeId}`, - { - method: 'PUT', - params: { - userId: window.API.currentUser.id, - badgeId: params.badgeId, - hidden: params.hidden, - showcased: params.showcased - } + return request(`users/${getCurrentUserId()}/badges/${params.badgeId}`, { + method: 'PUT', + params: { + userId: getCurrentUserId(), + badgeId: params.badgeId, + hidden: params.hidden, + showcased: params.showcased } - ).then((json) => { + }).then((json) => { const args = { json, params }; - // window.API.$emit('BADGE:UPDATE', args); return args; }); }, getVisits() { - return window.API.call('visits', { + return request('visits', { method: 'GET' }).then((json) => { const args = { json }; - // window.API.$emit('VISITS', args); return args; }); }, deleteFile(fileId) { - return window.API.call(`file/${fileId}`, { + return request(`file/${fileId}`, { method: 'DELETE' }).then((json) => { const args = { @@ -207,7 +202,7 @@ const miscReq = { // * @returns {Promise<{json: any, params}>} // */ // sendBoop(params) { - // return window.API.call(`users/${params.userId}/boop`, { + // return request(`users/${params.userId}/boop`, { // method: 'POST', // params // }).then((json) => { diff --git a/src/api/notification.js b/src/api/notification.js index 8387d834..f6550d26 100644 --- a/src/api/notification.js +++ b/src/api/notification.js @@ -1,4 +1,9 @@ -// #region | API: Notification +import { request } from '../service/request'; +import { useGroupStore, useNotificationStore } from '../stores'; + +function getGalleryStore() { + return useGroupStore(); +} const notificationReq = { /** @typedef {{ @@ -17,7 +22,7 @@ const notificationReq = { * @returns {Promise<{json: any, params}>} */ getNotifications(params) { - return window.API.call('auth/user/notifications', { + return request('auth/user/notifications', { method: 'GET', params }).then((json) => { @@ -25,13 +30,13 @@ const notificationReq = { json, params }; - window.API.$emit('NOTIFICATION:LIST', args); + return args; }); }, getHiddenFriendRequests(params) { - return window.API.call('auth/user/notifications', { + return request('auth/user/notifications', { method: 'GET', params: { type: 'friendRequest', @@ -43,13 +48,12 @@ const notificationReq = { json, params }; - window.API.$emit('NOTIFICATION:LIST:HIDDEN', args); return args; }); }, getNotificationsV2(params) { - return window.API.call('notifications', { + return request('notifications', { method: 'GET', params }).then((json) => { @@ -57,7 +61,6 @@ const notificationReq = { json, params }; - window.API.$emit('NOTIFICATION:V2:LIST', args); return args; }); }, @@ -80,7 +83,7 @@ const notificationReq = { * @return { Promise<{json: any, params}> } */ sendInvite(params, receiverUserId) { - return window.API.call(`invite/${receiverUserId}`, { + return request(`invite/${receiverUserId}`, { method: 'POST', params }).then((json) => { @@ -89,28 +92,26 @@ const notificationReq = { params, receiverUserId }; - window.API.$emit('NOTIFICATION:INVITE:SEND', args); return args; }); }, sendInvitePhoto(params, receiverUserId) { - return window.API.call(`invite/${receiverUserId}/photo`, { + return request(`invite/${receiverUserId}/photo`, { uploadImageLegacy: true, postData: JSON.stringify(params), - imageData: window.$app.uploadImage + imageData: getGalleryStore().uploadImage }).then((json) => { const args = { json, params, receiverUserId }; - window.API.$emit('NOTIFICATION:INVITE:PHOTO:SEND', args); return args; }); }, sendRequestInvite(params, receiverUserId) { - return window.API.call(`requestInvite/${receiverUserId}`, { + return request(`requestInvite/${receiverUserId}`, { method: 'POST', params }).then((json) => { @@ -119,29 +120,27 @@ const notificationReq = { params, receiverUserId }; - window.API.$emit('NOTIFICATION:REQUESTINVITE:SEND', args); return args; }); }, sendRequestInvitePhoto(params, receiverUserId) { - return window.API.call(`requestInvite/${receiverUserId}/photo`, { + return request(`requestInvite/${receiverUserId}/photo`, { uploadImageLegacy: true, postData: JSON.stringify(params), - imageData: window.$app.uploadImage + imageData: getGalleryStore().uploadImage }).then((json) => { const args = { json, params, receiverUserId }; - window.API.$emit('NOTIFICATION:REQUESTINVITE:PHOTO:SEND', args); return args; }); }, sendInviteResponse(params, inviteId) { - return window.API.call(`invite/${inviteId}/response`, { + return request(`invite/${inviteId}/response`, { method: 'POST', params, inviteId @@ -151,16 +150,15 @@ const notificationReq = { params, inviteId }; - window.API.$emit('INVITE:RESPONSE:SEND', args); return args; }); }, sendInviteResponsePhoto(params, inviteId) { - return window.API.call(`invite/${inviteId}/response/photo`, { + return request(`invite/${inviteId}/response/photo`, { uploadImageLegacy: true, postData: JSON.stringify(params), - imageData: window.$app.uploadImage, + imageData: getGalleryStore().uploadImage, inviteId }).then((json) => { const args = { @@ -168,7 +166,6 @@ const notificationReq = { params, inviteId }; - window.API.$emit('INVITE:RESPONSE:PHOTO:SEND', args); return args; }); }, @@ -178,7 +175,7 @@ const notificationReq = { * @return { Promise<{json: any, params}> } */ acceptFriendRequestNotification(params) { - return window.API.call( + return request( `auth/user/notifications/${params.notificationId}/accept`, { method: 'PUT' @@ -189,13 +186,13 @@ const notificationReq = { json, params }; - window.API.$emit('NOTIFICATION:ACCEPT', args); + useNotificationStore().handleNotificationAccept(args); return args; }) .catch((err) => { // if friend request could not be found, delete it if (err && err.message && err.message.includes('404')) { - window.API.$emit('NOTIFICATION:HIDE', { params }); + useNotificationStore().handleNotificationHide({ params }); } }); }, @@ -205,7 +202,7 @@ const notificationReq = { * @return { Promise<{json: any, params}> } */ hideNotification(params) { - return window.API.call( + return request( `auth/user/notifications/${params.notificationId}/hide`, { method: 'PUT' @@ -215,13 +212,11 @@ const notificationReq = { json, params }; - window.API.$emit('NOTIFICATION:HIDE', args); + useNotificationStore().handleNotificationHide(args); return args; }); }, - // ------------------- need to test ------------------- - /** * @param {{ * notificationId: string, @@ -231,32 +226,14 @@ const notificationReq = { * @return { Promise<{json: any, params}> } */ sendNotificationResponse(params) { - return window.API.call( - `notifications/${params.notificationId}/respond`, - { - method: 'POST', - params - } - ) - .then((json) => { - const args = { - json, - params - }; - window.API.$emit('NOTIFICATION:RESPONSE', args); - return args; - }) - .catch((err) => { - // TODO: need to test - // something went wrong, lets assume it's already expired - window.API.$emit('NOTIFICATION:HIDE', { params }); - notificationReq.hideNotificationV2(params.notificationId); - throw err; - }); + return request(`notifications/${params.notificationId}/respond`, { + method: 'POST', + params + }); }, - // use in sendNotificationResponse + hideNotificationV2(notificationId) { - return window.API.call(`notifications/${notificationId}`, { + return request(`notifications/${notificationId}`, { method: 'DELETE' }).then((json) => { const args = { @@ -265,16 +242,12 @@ const notificationReq = { notificationId } }; - // useless - // window.API.$emit('NOTIFICATION:V2:HIDE', args); return args; }); } - // ------------------ look like no place use these requests ------------------ - // sendInviteGalleryPhoto(params, receiverUserId) { - // return window.API.call(`invite/${receiverUserId}/photo`, { + // return request(`invite/${receiverUserId}/photo`, { // method: 'POST', // params // }).then((json) => { @@ -283,13 +256,13 @@ const notificationReq = { // params, // receiverUserId // }; - // window.API.$emit('NOTIFICATION:INVITE:GALLERYPHOTO:SEND', args); + // API.$emit('NOTIFICATION:INVITE:GALLERYPHOTO:SEND', args); // return args; // }); // }, // API.clearNotifications = function () { - // return this.call('auth/user/notifications/clear', { + // return request('auth/user/notifications/clear', { // method: 'PUT' // }).then((json) => { // var args = { diff --git a/src/api/playerModeration.js b/src/api/playerModeration.js index a28aa020..2906d15a 100644 --- a/src/api/playerModeration.js +++ b/src/api/playerModeration.js @@ -1,14 +1,13 @@ -// #region | API: PlayerModeration +import { request } from '../service/request'; const playerModerationReq = { getPlayerModerations() { - return window.API.call('auth/user/playermoderations', { + return request('auth/user/playermoderations', { method: 'GET' }).then((json) => { const args = { json }; - window.API.$emit('PLAYER-MODERATION:LIST', args); return args; }); }, @@ -19,7 +18,7 @@ const playerModerationReq = { */ // old-way: POST auth/user/blocks {blocked:userId} sendPlayerModeration(params) { - return window.API.call('auth/user/playermoderations', { + return request('auth/user/playermoderations', { method: 'POST', params }).then((json) => { @@ -27,7 +26,6 @@ const playerModerationReq = { json, params }; - // window.API.$emit('PLAYER-MODERATION:SEND', args); return args; }); }, @@ -38,7 +36,7 @@ const playerModerationReq = { */ // old-way: PUT auth/user/unblocks {blocked:userId} deletePlayerModeration(params) { - return window.API.call('auth/user/unplayermoderate', { + return request('auth/user/unplayermoderate', { method: 'PUT', params }).then((json) => { @@ -46,11 +44,9 @@ const playerModerationReq = { json, params }; - window.API.$emit('PLAYER-MODERATION:DELETE', args); return args; }); } }; -// #endregion export default playerModerationReq; diff --git a/src/api/prop.js b/src/api/prop.js index 939aa2b2..f2de5ca1 100644 --- a/src/api/prop.js +++ b/src/api/prop.js @@ -1,10 +1,12 @@ +import { request } from '../service/request'; + const propReq = { /** * @param {{ propId: string }} params * @returns {Promise<{json: any, params}>} */ getProp(params) { - return window.API.call(`props/${params.propId}`, { + return request(`props/${params.propId}`, { method: 'GET', params }).then((json) => { diff --git a/src/api/user.js b/src/api/user.js index 578289fb..c816ad41 100644 --- a/src/api/user.js +++ b/src/api/user.js @@ -1,13 +1,19 @@ -// #region | API: User +import { request } from '../service/request'; +import { useUserStore } from '../stores'; + +function getCurrentUserId() { + return useUserStore().currentUser.id; +} const userReq = { /** * Fetch user from API. - * @param {{ userId: string }} params identifier of registered user - * @returns {Promise<{json: any, params}>} + * identifier of registered user + * @type {import('../types/user').getUser} */ getUser(params) { - return window.API.call(`users/${params.userId}`, { + const userStore = useUserStore(); + return request(`users/${params.userId}`, { method: 'GET' }).then((json) => { if (!json) { @@ -19,7 +25,7 @@ const userReq = { json, params }; - window.API.$emit('USER', args); + args.ref = userStore.applyUser(json); return args; }); }, @@ -30,10 +36,17 @@ const userReq = { * @returns {Promise<{json: any, params}>} */ getCachedUser(params) { + const userStore = useUserStore(); return new Promise((resolve, reject) => { - const ref = window.API.cachedUsers.get(params.userId); + const ref = userStore.cachedUsers.get(params.userId); if (typeof ref === 'undefined') { - userReq.getUser(params).catch(reject).then(resolve); + userReq + .getUser(params) + .catch(reject) + .then((args) => { + args.ref = userStore.applyUser(args.json); + resolve(args); + }); } else { resolve({ cache: true, @@ -59,7 +72,7 @@ const userReq = { * @returns {Promise<{json: any, params}>} */ getUsers(params) { - return window.API.call('users', { + return request('users', { method: 'GET', params }).then((json) => { @@ -67,7 +80,6 @@ const userReq = { json, params }; - window.API.$emit('USER:LIST', args); return args; }); }, @@ -77,7 +89,8 @@ const userReq = { * @returns {Promise<{json: any, params}>} */ addUserTags(params) { - return window.API.call(`users/${window.API.currentUser.id}/addTags`, { + const userStore = useUserStore(); + return request(`users/${getCurrentUserId()}/addTags`, { method: 'POST', params }).then((json) => { @@ -85,7 +98,7 @@ const userReq = { json, params }; - window.API.$emit('USER:CURRENT:SAVE', args); + userStore.applyCurrentUser(json); return args; }); }, @@ -95,18 +108,16 @@ const userReq = { * @returns {Promise<{json: any, params}>} */ removeUserTags(params) { - return window.API.call( - `users/${window.API.currentUser.id}/removeTags`, - { - method: 'POST', - params - } - ).then((json) => { + const userStore = useUserStore(); + return request(`users/${getCurrentUserId()}/removeTags`, { + method: 'POST', + params + }).then((json) => { const args = { json, params }; - window.API.$emit('USER:CURRENT:SAVE', args); + userStore.applyCurrentUser(json); return args; }); }, @@ -116,7 +127,7 @@ const userReq = { * @returns {Promise<{json: any, params}>} */ getUserFeedback(params) { - return window.API.call(`users/${params.userId}/feedback`, { + return request(`users/${params.userId}/feedback`, { method: 'GET', params: { n: 100 @@ -126,7 +137,6 @@ const userReq = { json, params }; - // window.API.$emit('USER:FEEDBACK', args); return args; }); }, @@ -144,15 +154,16 @@ const userReq = { * @returns {Promise<{json: any, params}>} */ saveCurrentUser(params) { - return window.API.call(`users/${window.API.currentUser.id}`, { + const userStore = useUserStore(); + return request(`users/${getCurrentUserId()}`, { method: 'PUT', params }).then((json) => { - var args = { + const args = { json, params }; - window.API.$emit('USER:CURRENT:SAVE', args); + userStore.applyCurrentUser(json); return args; }); }, @@ -162,7 +173,7 @@ const userReq = { * @returns {Promise<{json: any, params}>} */ getUserNotes(params) { - return window.API.call(`userNotes`, { + return request(`userNotes`, { method: 'GET', params }).then((json) => { @@ -170,11 +181,9 @@ const userReq = { json, params }; - // window.API.$emit('USER:NOTES', args); return args; }); } }; -// #endregion export default userReq; diff --git a/src/api/vrcPlusIcon.js b/src/api/vrcPlusIcon.js index fae0bfe6..6b994093 100644 --- a/src/api/vrcPlusIcon.js +++ b/src/api/vrcPlusIcon.js @@ -1,8 +1,8 @@ -// #region | App: VRCPlus Icons +import { request } from '../service/request'; const VRCPlusIconsReq = { getFileList(params) { - return window.API.call('files', { + return request('files', { method: 'GET', params }).then((json) => { @@ -10,7 +10,18 @@ const VRCPlusIconsReq = { json, params }; - window.API.$emit('FILES:LIST', args); + return args; + }); + }, + + deleteFile(fileId) { + return request(`file/${fileId}`, { + method: 'DELETE' + }).then((json) => { + const args = { + json, + fileId + }; return args; }); }, @@ -19,7 +30,7 @@ const VRCPlusIconsReq = { const params = { tag: 'icon' }; - return window.API.call('file/image', { + return request('file/image', { uploadImage: true, matchingDimensions: true, postData: JSON.stringify(params), @@ -29,15 +40,12 @@ const VRCPlusIconsReq = { json, params }; - window.API.$emit('VRCPLUSICON:ADD', args); return args; }); } - // unused - // images.pug line 63 // deleteFileVersion(params) { - // return window.API.call(`file/${params.fileId}/${params.version}`, { + // return request(`file/${params.fileId}/${params.version}`, { // method: 'DELETE' // }).then((json) => { // const args = { @@ -49,6 +57,4 @@ const VRCPlusIconsReq = { // } }; -// #endregion - export default VRCPlusIconsReq; diff --git a/src/api/vrcPlusImage.js b/src/api/vrcPlusImage.js index 2ee36ab2..e4f3510e 100644 --- a/src/api/vrcPlusImage.js +++ b/src/api/vrcPlusImage.js @@ -1,9 +1,15 @@ +import { request } from '../service/request'; +import { useUserStore } from '../stores'; + +function getCurrentUserId() { + return useUserStore().currentUser.id; +} const vrcPlusImageReq = { uploadGalleryImage(imageData) { const params = { tag: 'gallery' }; - return window.API.call('file/image', { + return request('file/image', { uploadImage: true, matchingDimensions: false, postData: JSON.stringify(params), @@ -13,13 +19,12 @@ const vrcPlusImageReq = { json, params }; - window.API.$emit('GALLERYIMAGE:ADD', args); return args; }); }, uploadSticker(imageData, params) { - return window.API.call('file/image', { + return request('file/image', { uploadImage: true, matchingDimensions: true, postData: JSON.stringify(params), @@ -29,13 +34,12 @@ const vrcPlusImageReq = { json, params }; - window.API.$emit('STICKER:ADD', args); return args; }); }, getPrints(params) { - return window.API.call(`prints/user/${window.API.currentUser.id}`, { + return request(`prints/user/${getCurrentUserId()}`, { method: 'GET', params }).then((json) => { @@ -48,20 +52,19 @@ const vrcPlusImageReq = { }, deletePrint(printId) { - return window.API.call(`prints/${printId}`, { + return request(`prints/${printId}`, { method: 'DELETE' }).then((json) => { const args = { json, printId }; - // window.API.$emit('PRINT:DELETE', args); return args; }); }, uploadPrint(imageData, cropWhiteBorder, params) { - return window.API.call('prints', { + return request('prints', { uploadImagePrint: true, cropWhiteBorder, postData: JSON.stringify(params), @@ -71,26 +74,24 @@ const vrcPlusImageReq = { json, params }; - window.API.$emit('PRINT:ADD', args); return args; }); }, getPrint(params) { - return window.API.call(`prints/${params.printId}`, { + return request(`prints/${params.printId}`, { method: 'GET' }).then((json) => { const args = { json, params }; - window.API.$emit('PRINT', args); return args; }); }, uploadEmoji(imageData, params) { - return window.API.call('file/image', { + return request('file/image', { uploadImage: true, matchingDimensions: true, postData: JSON.stringify(params), @@ -100,15 +101,12 @@ const vrcPlusImageReq = { json, params }; - window.API.$emit('EMOJI:ADD', args); return args; }); } - // ----------- no place uses this function ------------ - // editPrint(params) { - // return window.API.call(`prints/${params.printId}`, { + // return request(`prints/${params.printId}`, { // method: 'POST', // params // }).then((json) => { @@ -116,7 +114,7 @@ const vrcPlusImageReq = { // json, // params // }; - // window.API.$emit('PRINT:EDIT', args); + // API.$emit('PRINT:EDIT', args); // return args; // }); // }, diff --git a/src/api/world.js b/src/api/world.js index 9df72e13..fff55ac7 100644 --- a/src/api/world.js +++ b/src/api/world.js @@ -1,4 +1,5 @@ -// #region | API: World +import { request } from '../service/request'; +import { useWorldStore } from '../stores'; const worldReq = { /** @@ -6,14 +7,15 @@ const worldReq = { * @returns {Promise<{json: any, params}>} */ getWorld(params) { - return window.API.call(`worlds/${params.worldId}`, { + const worldStore = useWorldStore(); + return request(`worlds/${params.worldId}`, { method: 'GET' }).then((json) => { const args = { json, params }; - window.API.$emit('WORLD', args); + args.ref = worldStore.applyWorld(json); return args; }); }, @@ -23,10 +25,17 @@ const worldReq = { * @returns {Promise<{json: any, params}>} */ getCachedWorld(params) { + const worldStore = useWorldStore(); return new Promise((resolve, reject) => { - const ref = window.API.cachedWorlds.get(params.worldId); + const ref = worldStore.cachedWorlds.get(params.worldId); if (typeof ref === 'undefined') { - worldReq.getWorld(params).catch(reject).then(resolve); + worldReq + .getWorld(params) + .catch(reject) + .then((args) => { + args.ref = worldStore.applyWorld(args.json); + resolve(args); + }); } else { resolve({ cache: true, @@ -57,11 +66,12 @@ const worldReq = { * @returns {Promise<{json: any, params, option}>} */ getWorlds(params, option) { + const worldStore = useWorldStore(); let endpoint = 'worlds'; if (typeof option !== 'undefined') { endpoint = `worlds/${option}`; } - return window.API.call(endpoint, { + return request(endpoint, { method: 'GET', params }).then((json) => { @@ -70,7 +80,9 @@ const worldReq = { params, option }; - window.API.$emit('WORLD:LIST', args); + for (const json of args.json) { + worldStore.applyWorld(json); + } return args; }); }, @@ -79,14 +91,13 @@ const worldReq = { * @returns {Promise<{json: any, params}>} */ deleteWorld(params) { - return window.API.call(`worlds/${params.worldId}`, { + return request(`worlds/${params.worldId}`, { method: 'DELETE' }).then((json) => { const args = { json, params }; - window.API.$emit('WORLD:DELETE', args); return args; }); }, @@ -96,7 +107,8 @@ const worldReq = { * @returns {Promise<{json: any, params}>} */ saveWorld(params) { - return window.API.call(`worlds/${params.id}`, { + const worldStore = useWorldStore(); + return request(`worlds/${params.id}`, { method: 'PUT', params }).then((json) => { @@ -104,7 +116,7 @@ const worldReq = { json, params }; - window.API.$emit('WORLD:SAVE', args); + args.ref = worldStore.applyWorld(json); return args; }); }, @@ -114,7 +126,8 @@ const worldReq = { * @returns {Promise<{json: any, params}>} */ publishWorld(params) { - return window.API.call(`worlds/${params.worldId}/publish`, { + const worldStore = useWorldStore(); + return request(`worlds/${params.worldId}/publish`, { method: 'PUT', params }).then((json) => { @@ -122,7 +135,7 @@ const worldReq = { json, params }; - window.API.$emit('WORLD:SAVE', args); + args.ref = worldStore.applyWorld(json); return args; }); }, @@ -132,7 +145,8 @@ const worldReq = { * @returns {Promise<{json: any, params}>} */ unpublishWorld(params) { - return window.API.call(`worlds/${params.worldId}/publish`, { + const worldStore = useWorldStore(); + return request(`worlds/${params.worldId}/publish`, { method: 'DELETE', params }).then((json) => { @@ -140,12 +154,10 @@ const worldReq = { json, params }; - window.API.$emit('WORLD:SAVE', args); + args.ref = worldStore.applyWorld(json); return args; }); } }; -// #endregion - export default worldReq; diff --git a/src/app.js b/src/app.js index 0c625ec6..f38e7aec 100644 --- a/src/app.js +++ b/src/app.js @@ -4,14159 +4,20 @@ // This work is licensed under the terms of the MIT license. // For a copy, see . -// #region | Imports -import '@fontsource/noto-sans-kr'; -import '@fontsource/noto-sans-jp'; -import '@fontsource/noto-sans-sc'; -import '@fontsource/noto-sans-tc'; -import '@infolektuell/noto-color-emoji'; -import dayjs from 'dayjs'; -import duration from 'dayjs/plugin/duration'; -import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'; -import timezone from 'dayjs/plugin/timezone'; -import utc from 'dayjs/plugin/utc'; -import ElementUI from 'element-ui'; -import Noty from 'noty'; import Vue from 'vue'; -import { DataTables } from 'vue-data-tables'; -import VueI18n from 'vue-i18n'; -import { createI18n } from 'vue-i18n-bridge'; -import VueLazyload from 'vue-lazyload'; -import * as workerTimers from 'worker-timers'; -import 'default-passive-events'; -import { - avatarModerationRequest, - avatarRequest, - favoriteRequest, - friendRequest, - groupRequest, - imageRequest, - instanceRequest, - inventoryRequest, - inviteMessagesRequest, - miscRequest, - notificationRequest, - playerModerationRequest, - userRequest, - vrcPlusIconRequest, - vrcPlusImageRequest, - worldRequest -} from './api'; - -import pugTemplate from './app.pug'; - -// API classes -import _config from './classes/API/config.js'; -import _apiInit from './classes/apiInit.js'; -import _apiLogin from './classes/apiLogin.js'; -import _apiRequestHandler from './classes/apiRequestHandler.js'; -import _currentUser from './classes/currentUser.js'; -import _discordRpc from './classes/discordRpc.js'; -import _feed from './classes/feed.js'; -import _gameLog from './classes/gameLog.js'; -import _gameRealtimeLogging from './classes/gameRealtimeLogging.js'; -import _groups from './classes/groups.js'; -import _inventory from './classes/inventory.js'; -import _languages from './classes/languages.js'; -import _memos from './classes/memos.js'; -import _prompts from './classes/prompts.js'; -import _restoreFriendOrder from './classes/restoreFriendOrder.js'; - -// main app classes -import _sharedFeed from './classes/sharedFeed.js'; -import _uiComponents from './classes/uiComponents.js'; -import _updateLoop from './classes/updateLoop.js'; - -import { userNotes } from './classes/userNotes.js'; -import $utils from './classes/utils.js'; -import _vrcRegistry from './classes/vrcRegistry.js'; -import _vrcxJsonStorage from './classes/vrcxJsonStorage.js'; -import _vrcxNotifications from './classes/vrcxNotifications.js'; -import _vrcxUpdater from './classes/vrcxUpdater.js'; -import _websocket from './classes/websocket.js'; -import AvatarDialog from './components/dialogs/AvatarDialog/AvatarDialog.vue'; -import ChooseFavoriteGroupDialog from './components/dialogs/ChooseFavoriteGroupDialog.vue'; -import FullscreenImageDialog from './components/dialogs/FullscreenImageDialog.vue'; -import GalleryDialog from './components/dialogs/GalleryDialog.vue'; -import GroupDialog from './components/dialogs/GroupDialog/GroupDialog.vue'; -import InviteGroupDialog from './components/dialogs/InviteGroupDialog.vue'; -import LaunchDialog from './components/dialogs/LaunchDialog.vue'; -import PreviousInstancesInfoDialog from './components/dialogs/PreviousInstancesDialog/PreviousInstancesInfoDialog.vue'; - -import SafeDialog from './components/dialogs/SafeDialog.vue'; -import UserDialog from './components/dialogs/UserDialog/UserDialog.vue'; -import VRCXUpdateDialog from './components/dialogs/VRCXUpdateDialog.vue'; - -// dialogs -import WorldDialog from './components/dialogs/WorldDialog/WorldDialog.vue'; -import Location from './components/Location.vue'; -import NavMenu from './components/NavMenu.vue'; - -// components -import SimpleSwitch from './components/SimpleSwitch.vue'; -import { - compareUnityVersion, - getPlatformInfo, - storeAvatarImage -} from './composables/avatar/utils'; - -import { hasGroupPermission } from './composables/group/utils'; - -import { - displayLocation, - isRealInstance, - parseLocation -} from './composables/instance/utils'; -import { - _utils, - checkVRChatCache, - convertFileUrlToImageUrl, - deleteVRChatCache, - extractFileId, - extractFileVersion, - getAvailablePlatforms -} from './composables/shared/utils'; -import { userDialogGroupSortingOptions } from './composables/user/constants/userDialogGroupSortingOptions'; -import { - getPrintFileName, - getPrintLocalDate, - getEmojiFileName, - languageClass -} from './composables/user/utils'; -import InteropApi from './ipc-electron/interopApi.js'; -import * as localizedStrings from './localization/localizedStrings.js'; - -// util classes -import configRepository from './service/config.js'; -import removeConfusables, { removeWhitespace } from './service/confusables.js'; -import database from './service/database.js'; -import security from './service/security.js'; -import webApiService from './service/webapi.js'; -import ChartsTab from './views/Charts/Charts.vue'; -import AvatarImportDialog from './views/Favorites/dialogs/AvatarImportDialog.vue'; -import FriendImportDialog from './views/Favorites/dialogs/FriendImportDialog.vue'; -import WorldImportDialog from './views/Favorites/dialogs/WorldImportDialog.vue'; -import FavoritesTab from './views/Favorites/Favorites.vue'; -import FeedTab from './views/Feed/Feed.vue'; -import FriendListTab from './views/FriendList/FriendList.vue'; -import FriendLogTab from './views/FriendLog/FriendLog.vue'; -import GameLogTab from './views/GameLog/GameLog.vue'; - -import LoginPage from './views/Login/Login.vue'; - -// tabs -import ModerationTab from './views/Moderation/Moderation.vue'; -import NotificationTab from './views/Notifications/Notification.vue'; -import ChatboxBlacklistDialog from './views/PlayerList/dialogs/ChatboxBlacklistDialog.vue'; -import PlayerListTab from './views/PlayerList/PlayerList.vue'; -import DiscordNamesDialog from './views/Profile/dialogs/DiscordNamesDialog.vue'; -import EditInviteMessageDialog from './views/Profile/dialogs/EditInviteMessageDialog.vue'; -import ExportAvatarsListDialog from './views/Profile/dialogs/ExportAvatarsListDialog.vue'; -import ExportFriendsListDialog from './views/Profile/dialogs/ExportFriendsListDialog.vue'; -import ProfileTab from './views/Profile/Profile.vue'; -import SearchTab from './views/Search/Search.vue'; -import AvatarProviderDialog from './views/Settings/dialogs/AvatarProviderDialog.vue'; -import ChangelogDialog from './views/Settings/dialogs/ChangelogDialog.vue'; -import FeedFiltersDialog from './views/Settings/dialogs/FeedFiltersDialog.vue'; -import LaunchOptionsDialog from './views/Settings/dialogs/LaunchOptionsDialog.vue'; -import NoteExportDialog from './views/Settings/dialogs/NoteExportDialog.vue'; -import NotificationPositionDialog from './views/Settings/dialogs/NotificationPositionDialog.vue'; -import OpenSourceSoftwareNoticeDialog from './views/Settings/dialogs/OpenSourceSoftwareNoticeDialog.vue'; -import PrimaryPasswordDialog from './views/Settings/dialogs/PrimaryPasswordDialog.vue'; -import RegistryBackupDialog from './views/Settings/dialogs/RegistryBackupDialog.vue'; -import ScreenshotMetadataDialog from './views/Settings/dialogs/ScreenshotMetadataDialog.vue'; -import VRChatConfigDialog from './views/Settings/dialogs/VRChatConfigDialog.vue'; -import YouTubeApiDialog from './views/Settings/dialogs/YouTubeApiDialog.vue'; -import SideBar from './views/SideBar/SideBar.vue'; - -// #endregion - -// some workaround for failing to get voice list first run -speechSynthesis.getVoices(); +import './bootstrap'; +import App from './App.vue'; +import { pinia } from './stores'; console.log(`isLinux: ${LINUX}`); // #region | Hey look it's most of VRCX! -(async function () { - // #region | Init Cef C# bindings - if (WINDOWS) { - await CefSharp.BindObjectAsync( - 'AppApi', - 'WebApi', - 'SharedVariable', - 'VRCXStorage', - 'SQLite', - 'LogWatcher', - 'Discord', - 'AssetBundleManager' - ); - } else { - window.AppApi = InteropApi.AppApiElectron; - window.WebApi = InteropApi.WebApi; - window.SharedVariable = InteropApi.SharedVariable; - window.VRCXStorage = InteropApi.VRCXStorage; - window.SQLite = InteropApi.SQLiteLegacy; - window.LogWatcher = InteropApi.LogWatcher; - window.Discord = InteropApi.Discord; - window.AssetBundleManager = InteropApi.AssetBundleManager; - } +// prompt: 'Please clean up and refactor the VRCX codebase.' - // #region | localization - Vue.use(VueI18n, { bridge: true }); - const i18n = createI18n( - { - locale: 'en', - fallbackLocale: 'en', - messages: localizedStrings, - legacy: false, - globalInjection: true, - missingWarn: false, - warnHtmlMessage: false, - fallbackWarn: false - }, - VueI18n - ); - const $t = i18n.global.t; - Vue.use(i18n); - Vue.use(ElementUI, { - i18n: (key, value) => i18n.global.t(key, value) - }); - // #endregion +const $app = new Vue({ + pinia, + render: (h) => h(App) +}).$mount('#root'); - // everything in this program is global stored in $app, I hate it, it is what it is - let $app = {}; - const API = new _apiInit($app); - const vrcxJsonStorage = new _vrcxJsonStorage(VRCXStorage); - - let vrcxClasses = { - // other classes - API, - apiRequestHandler: new _apiRequestHandler($app, API, $t, webApiService), - uiComponents: new _uiComponents($app, API, $t), - webSocket: new _websocket($app, API, $t), - // main classes - sharedFeed: new _sharedFeed($app, API, $t), - prompts: new _prompts($app, API, $t), - vrcxNotifications: new _vrcxNotifications($app, API, $t), - apiLogin: new _apiLogin($app, API, $t, webApiService), - currentUser: new _currentUser($app, API, $t), - updateLoop: new _updateLoop($app, API, $t), - discordRpc: new _discordRpc($app, API, $t), - vrcxUpdater: new _vrcxUpdater($app, API, $t), - gameLog: new _gameLog($app, API, $t), - gameRealtimeLogging: new _gameRealtimeLogging($app, API, $t), - feed: new _feed($app, API, $t), - memos: new _memos($app, API, $t), - config: new _config($app, API, $t), - languages: new _languages($app, API, $t), - groups: new _groups($app, API, $t), - vrcRegistry: new _vrcRegistry($app, API, $t), - restoreFriendOrder: new _restoreFriendOrder($app, API, $t), - inventory: new _inventory($app, API, $t) - }; - - await configRepository.init(); - - const app = { - template: pugTemplate, - data: { - API, - isGameRunning: false, - isGameNoVR: true, - isSteamVRRunning: false, - isHmdAfk: false, - isRunningUnderWine: false, - appVersion: '', - latestAppVersion: '', - shiftHeld: false - }, - i18n, - computed: {}, - methods: { - ...$utils - }, - watch: {}, - components: { - LoginPage, - // tabs - ModerationTab, - ChartsTab, - FriendListTab, - FavoritesTab, - NotificationTab, - SearchTab, - // - others - SideBar, - NavMenu, - FriendLogTab, - GameLogTab, - FeedTab, - ProfileTab, - PlayerListTab, - - // components - // - common - Location, - - // - settings - SimpleSwitch, - - // - dialogs - // - previous instances - PreviousInstancesInfoDialog, - UserDialog, - // - world - WorldDialog, - // - group - GroupDialog, - InviteGroupDialog, - // - avatar - AvatarDialog, - // - favorites - FriendImportDialog, - WorldImportDialog, - AvatarImportDialog, - // - favorites dialog - ChooseFavoriteGroupDialog, - ExportFriendsListDialog, - ExportAvatarsListDialog, - // - launch - LaunchDialog, - // - player list - ChatboxBlacklistDialog, - // - profile - DiscordNamesDialog, - // - settings - FeedFiltersDialog, - LaunchOptionsDialog, - OpenSourceSoftwareNoticeDialog, - ChangelogDialog, - VRCXUpdateDialog, - ScreenshotMetadataDialog, - EditInviteMessageDialog, - NoteExportDialog, - VRChatConfigDialog, - YouTubeApiDialog, - NotificationPositionDialog, - AvatarProviderDialog, - RegistryBackupDialog, - PrimaryPasswordDialog, - FullscreenImageDialog, - GalleryDialog - }, - provide() { - return { - API, - friends: this.friends, - showUserDialog: this.showUserDialog, - adjustDialogZ: this.adjustDialogZ, - getWorldName: this.getWorldName, - userImage: this.userImage, - userStatusClass: this.userStatusClass, - getGroupName: this.getGroupName, - userImageFull: this.userImageFull, - showFullscreenImageDialog: this.showFullscreenImageDialog, - statusClass: this.statusClass, - openExternalLink: this.openExternalLink, - showWorldDialog: this.showWorldDialog, - showAvatarDialog: this.showAvatarDialog, - showPreviousInstancesInfoDialog: - this.showPreviousInstancesInfoDialog, - showLaunchDialog: this.showLaunchDialog, - showFavoriteDialog: this.showFavoriteDialog, - displayPreviousImages: this.displayPreviousImages, - languageClass: this.languageClass, - showGroupDialog: this.showGroupDialog, - showGallerySelectDialog: this.showGallerySelectDialog, - showGalleryDialog: this.showGalleryDialog, - getImageUrlFromImageId: this.getImageUrlFromImageId, - getAvatarGallery: this.getAvatarGallery, - inviteImageUpload: this.inviteImageUpload, - clearInviteImageUpload: this.clearInviteImageUpload, - isLinux: this.isLinux, - openFolderGeneric: this.openFolderGeneric, - deleteVRChatCache: this.deleteVRChatCache - }; - }, - el: '#root', - beforeMount() { - this.changeThemeMode(); - }, - async mounted() { - await this.initLanguage(); - try { - this.isRunningUnderWine = await AppApi.IsRunningUnderWine(); - } catch (err) { - console.error(err); - } - await AppApi.SetUserAgent(); - await this.loadVrcxId(); - this.appVersion = await AppApi.GetVersion(); - await this.compareAppVersion(); - await this.setBranch(); - if (this.autoUpdateVRCX !== 'Off') { - this.checkForVRCXUpdate(); - } - await AppApi.CheckGameRunning(); - this.isGameNoVR = await configRepository.getBool('isGameNoVR'); - await AppApi.SetAppLauncherSettings( - this.enableAppLauncher, - this.enableAppLauncherAutoClose - ); - API.$on('SHOW_WORLD_DIALOG_SHORTNAME', (tag) => - this.verifyShortName('', tag) - ); - this.updateLoop(); - this.getGameLogTable(); - this.refreshCustomCss(); - this.refreshCustomScript(); - this.checkVRChatDebugLogging(); - this.checkAutoBackupRestoreVrcRegistry(); - await this.migrateStoredUsers(); - this.loginForm.savedCredentials = - (await configRepository.getString('savedCredentials')) !== null - ? JSON.parse( - await configRepository.getString('savedCredentials') - ) - : {}; - this.loginForm.lastUserLoggedIn = - await configRepository.getString('lastUserLoggedIn'); - this.$nextTick(async function () { - this.$el.style.display = ''; - if ( - !this.enablePrimaryPassword && - (await configRepository.getString('lastUserLoggedIn')) !== - null - ) { - var user = - this.loginForm.savedCredentials[ - this.loginForm.lastUserLoggedIn - ]; - if (user?.loginParmas?.endpoint) { - API.endpointDomain = user.loginParmas.endpoint; - API.websocketDomain = user.loginParmas.websocket; - } - // login at startup - this.loginForm.loading = true; - API.getConfig() - .catch((err) => { - this.loginForm.loading = false; - throw err; - }) - .then((args) => { - API.getCurrentUser() - .finally(() => { - this.loginForm.loading = false; - }) - .catch((err) => { - this.nextCurrentUserRefresh = 60; // 1min - console.error(err); - }); - return args; - }); - } else { - this.loginForm.loading = false; - } - }); - if (LINUX) { - setTimeout(() => { - this.updateTTSVoices(); - }, 5000); - } - } - }; - for (let value of Object.values(vrcxClasses)) { - app.methods = { ...app.methods, ...value._methods }; - app.data = { ...app.data, ...value._data }; - } - app.methods = { ...app.methods, ..._utils }; - Object.assign($app, app); - - // #endregion - // #region | Init: drop/keyup event listeners - // Make sure file drops outside of the screenshot manager don't navigate to the file path dropped. - // This issue persists on prompts created with prompt(), unfortunately. Not sure how to fix that. - document.body.addEventListener('drop', function (e) { - e.preventDefault(); - }); - - document.addEventListener('keydown', function (e) { - if (e.shiftKey) { - $app.shiftHeld = true; - } - }); - - document.addEventListener('keyup', function (e) { - if (e.ctrlKey) { - if (e.key === 'I') { - $app.showConsole(); - } else if (e.key === 'r') { - location.reload(); - } - } else if (e.altKey && e.key === 'R') { - $app.refreshCustomCss(); - } - - if (!e.shiftKey) { - $app.shiftHeld = false; - } - }); - - addEventListener('wheel', (event) => { - if (event.ctrlKey) { - $app.getZoomLevel(); - } - }); - - // #endregion - - // #region | Init: Noty, Vue, Vue-Markdown, ElementUI, VueI18n, VueLazyLoad, Vue filters, dark stylesheet, dayjs - - Noty.overrideDefaults({ - animation: { - open: 'animate__animated animate__bounceInLeft', - close: 'animate__animated animate__bounceOutLeft' - }, - layout: 'bottomLeft', - theme: 'mint', - timeout: 6000 - }); - - Vue.filter('commaNumber', $utils.commaNumber); - Vue.filter('textToHex', $utils.textToHex); - - Vue.use(VueLazyload, { - preLoad: 1, - observer: true, - observerOptions: { - rootMargin: '0px', - threshold: 0 - }, - attempt: 3 - }); - - Vue.use(DataTables); - - Vue.component('safe-dialog', SafeDialog); - - dayjs.extend(duration); - dayjs.extend(utc); - dayjs.extend(timezone); - dayjs.extend(isSameOrAfter); - - // #endregion - - // #endregion - // #region | API: This is NOT all the api functions, not even close :( - - // #region | API: User - - // changeUserName: PUT users/${userId} {displayName: string, currentPassword: string} - // changeUserEmail: PUT users/${userId} {email: string, currentPassword: string} - // changePassword: PUT users/${userId} {password: string, currentPassword: string} - // updateTOSAggreement: PUT users/${userId} {acceptedTOSVersion: number} - - // 2FA - // removeTwoFactorAuth: DELETE auth/twofactorauth - // getTwoFactorAuthpendingSecret: POST auth/twofactorauth/totp/pending -> { qrCodeDataUrl: string, secret: string } - // verifyTwoFactorAuthPendingSecret: POST auth/twofactorauth/totp/pending/verify { code: string } -> { verified: bool, enabled: bool } - // cancelVerifyTwoFactorAuthPendingSecret: DELETE auth/twofactorauth/totp/pending - // getTwoFactorAuthOneTimePasswords: GET auth/user/twofactorauth/otp -> { otp: [ { code: string, used: bool } ] } - - // Account Link - // merge: PUT auth/user/merge {mergeToken: string} - // 링크됐다면 CurrentUser에 steamId, oculusId 값이 생기는듯 - // 스팀 계정으로 로그인해도 steamId, steamDetails에 값이 생김 - - // Password Recovery - // sendLink: PUT auth/password {email: string} - // setNewPassword: PUT auth/password {emailToken: string, id: string, password: string} - - API.cachedUsers = new Map(); - API.currentTravelers = new Map(); - - API.$on('USER:CURRENT:SAVE', function (args) { - this.$emit('USER:CURRENT', args); - }); - - API.$on('USER', function (args) { - if (!args?.json?.id) { - console.error('API.$on(USER) invalid args', args); - return; - } - if (args.json.state === 'online') { - args.ref = this.applyUser(args.json); // GPS - $app.updateFriend({ id: args.json.id, state: args.json.state }); // online/offline - } else { - $app.updateFriend({ id: args.json.id, state: args.json.state }); // online/offline - args.ref = this.applyUser(args.json); // GPS - } - }); - - API.$on('USER:LIST', function (args) { - for (var json of args.json) { - if (!json.displayName) { - console.error('getUsers gave us garbage', json); - continue; - } - this.$emit('USER', { - json, - params: { - userId: json.id - } - }); - } - }); - - API.applyUserTrustLevel = function (ref) { - ref.$isModerator = ref.developerType && ref.developerType !== 'none'; - ref.$isTroll = false; - ref.$isProbableTroll = false; - var trustColor = ''; - var { tags } = ref; - if (tags.includes('admin_moderator')) { - ref.$isModerator = true; - } - if (tags.includes('system_troll')) { - ref.$isTroll = true; - } - if (tags.includes('system_probable_troll') && !ref.$isTroll) { - ref.$isProbableTroll = true; - } - if (tags.includes('system_trust_veteran')) { - ref.$trustLevel = 'Trusted User'; - ref.$trustClass = 'x-tag-veteran'; - trustColor = 'veteran'; - ref.$trustSortNum = 5; - } else if (tags.includes('system_trust_trusted')) { - ref.$trustLevel = 'Known User'; - ref.$trustClass = 'x-tag-trusted'; - trustColor = 'trusted'; - ref.$trustSortNum = 4; - } else if (tags.includes('system_trust_known')) { - ref.$trustLevel = 'User'; - ref.$trustClass = 'x-tag-known'; - trustColor = 'known'; - ref.$trustSortNum = 3; - } else if (tags.includes('system_trust_basic')) { - ref.$trustLevel = 'New User'; - ref.$trustClass = 'x-tag-basic'; - trustColor = 'basic'; - ref.$trustSortNum = 2; - } else { - ref.$trustLevel = 'Visitor'; - ref.$trustClass = 'x-tag-untrusted'; - trustColor = 'untrusted'; - ref.$trustSortNum = 1; - } - if (ref.$isTroll || ref.$isProbableTroll) { - trustColor = 'troll'; - ref.$trustSortNum += 0.1; - } - if (ref.$isModerator) { - trustColor = 'vip'; - ref.$trustSortNum += 0.3; - } - if ($app.randomUserColours && $app.friendLogInitStatus) { - if (!ref.$userColour) { - $app.getNameColour(ref.id).then((colour) => { - ref.$userColour = colour; - }); - } - } else { - ref.$userColour = $app.trustColor[trustColor]; - } - }; - - API.applyUserLanguage = function (ref) { - if (!ref || !ref.tags || !$app.subsetOfLanguages) { - return; - } - - ref.$languages = []; - const languagePrefix = 'language_'; - const prefixLength = languagePrefix.length; - - for (const tag of ref.tags) { - if (tag.startsWith(languagePrefix)) { - const key = tag.substring(prefixLength); - const value = $app.subsetOfLanguages[key]; - - if (value !== undefined) { - ref.$languages.push({ key, value }); - } - } - } - }; - - API.applyPresenceLocation = function (ref) { - var presence = ref.presence; - if (isRealInstance(presence.world)) { - ref.$locationTag = `${presence.world}:${presence.instance}`; - } else { - ref.$locationTag = presence.world; - } - if (isRealInstance(presence.travelingToWorld)) { - ref.$travelingToLocation = `${presence.travelingToWorld}:${presence.travelingToInstance}`; - } else { - ref.$travelingToLocation = presence.travelingToWorld; - } - $app.updateCurrentUserLocation(); - }; - - API.applyPresenceGroups = function (ref) { - if (!this.currentUserGroupsInit) { - // wait for init before diffing - return; - } - var groups = ref.presence?.groups; - if (!groups) { - console.error('API.applyPresenceGroups: invalid groups', ref); - return; - } - if (groups.length === 0) { - // as it turns out, this is not the most trust worthly source of info - return; - } - - // update group list - for (var groupId of groups) { - if (!this.currentUserGroups.has(groupId)) { - $app.onGroupJoined(groupId); - } - } - for (var groupId of this.currentUserGroups.keys()) { - if (!groups.includes(groupId)) { - $app.onGroupLeft(groupId); - } - } - }; - - API.applyUser = function (json) { - var ref = this.cachedUsers.get(json.id); - if (json.statusDescription) { - json.statusDescription = $utils.replaceBioSymbols( - json.statusDescription - ); - json.statusDescription = $app.removeEmojis(json.statusDescription); - } - if (json.bio) { - json.bio = $utils.replaceBioSymbols(json.bio); - } - if (json.note) { - json.note = $utils.replaceBioSymbols(json.note); - } - if (json.currentAvatarImageUrl === $app.robotUrl) { - delete json.currentAvatarImageUrl; - delete json.currentAvatarThumbnailImageUrl; - } - if (typeof ref === 'undefined') { - ref = { - ageVerificationStatus: '', - ageVerified: false, - allowAvatarCopying: false, - badges: [], - bio: '', - bioLinks: [], - currentAvatarImageUrl: '', - currentAvatarTags: [], - currentAvatarThumbnailImageUrl: '', - date_joined: '', - developerType: '', - displayName: '', - friendKey: '', - friendRequestStatus: '', - id: '', - instanceId: '', - isFriend: false, - last_activity: '', - last_login: '', - last_mobile: null, - last_platform: '', - location: '', - platform: '', - note: null, // keep as null, to detect deleted notes - profilePicOverride: '', - profilePicOverrideThumbnail: '', - pronouns: '', - state: '', - status: '', - statusDescription: '', - tags: [], - travelingToInstance: '', - travelingToLocation: '', - travelingToWorld: '', - userIcon: '', - worldId: '', - // only in bulk request - fallbackAvatar: '', - // VRCX - $location: {}, - $location_at: Date.now(), - $online_for: Date.now(), - $travelingToTime: Date.now(), - $offline_for: '', - $active_for: Date.now(), - $isVRCPlus: false, - $isModerator: false, - $isTroll: false, - $isProbableTroll: false, - $trustLevel: 'Visitor', - $trustClass: 'x-tag-untrusted', - $userColour: '', - $trustSortNum: 1, - $languages: [], - $joinCount: 0, - $timeSpent: 0, - $lastSeen: '', - $nickName: '', - $previousLocation: '', - $customTag: '', - $customTagColour: '', - $friendNumber: 0, - // - ...json - }; - if ($app.lastLocation.playerList.has(json.id)) { - // update $location_at from instance join time - var player = $app.lastLocation.playerList.get(json.id); - ref.$location_at = player.joinTime; - ref.$online_for = player.joinTime; - } - if (ref.location === 'traveling') { - ref.$location = parseLocation(ref.travelingToLocation); - if ( - !this.currentTravelers.has(ref.id) && - ref.travelingToLocation - ) { - var travelRef = { - created_at: new Date().toJSON(), - ...ref - }; - this.currentTravelers.set(ref.id, travelRef); - $app.sharedFeed.pendingUpdate = true; - $app.updateSharedFeed(false); - $app.onPlayerTraveling(travelRef); - } - } else { - ref.$location = parseLocation(ref.location); - if (this.currentTravelers.has(ref.id)) { - this.currentTravelers.delete(ref.id); - $app.sharedFeed.pendingUpdate = true; - $app.updateSharedFeed(false); - } - } - if (ref.isFriend || ref.id === this.currentUser.id) { - // update instancePlayerCount - var newCount = $app.instancePlayerCount.get(ref.location); - if (typeof newCount === 'undefined') { - newCount = 0; - } - newCount++; - $app.instancePlayerCount.set(ref.location, newCount); - } - if ($app.customUserTags.has(json.id)) { - var tag = $app.customUserTags.get(json.id); - ref.$customTag = tag.tag; - ref.$customTagColour = tag.colour; - } else if (ref.$customTag) { - ref.$customTag = ''; - ref.$customTagColour = ''; - } - ref.$isVRCPlus = ref.tags.includes('system_supporter'); - this.applyUserTrustLevel(ref); - this.applyUserLanguage(ref); - this.cachedUsers.set(ref.id, ref); - } else { - var props = {}; - for (var prop in ref) { - if (ref[prop] !== Object(ref[prop])) { - props[prop] = true; - } - } - var $ref = { ...ref }; - Object.assign(ref, json); - ref.$isVRCPlus = ref.tags.includes('system_supporter'); - this.applyUserTrustLevel(ref); - this.applyUserLanguage(ref); - // traveling - if (ref.location === 'traveling') { - ref.$location = parseLocation(ref.travelingToLocation); - if (!this.currentTravelers.has(ref.id)) { - var travelRef = { - created_at: new Date().toJSON(), - ...ref - }; - this.currentTravelers.set(ref.id, travelRef); - $app.sharedFeed.pendingUpdate = true; - $app.updateSharedFeed(false); - $app.onPlayerTraveling(travelRef); - } - } else { - ref.$location = parseLocation(ref.location); - if (this.currentTravelers.has(ref.id)) { - this.currentTravelers.delete(ref.id); - $app.sharedFeed.pendingUpdate = true; - $app.updateSharedFeed(false); - } - } - for (var prop in ref) { - if (Array.isArray(ref[prop]) && Array.isArray($ref[prop])) { - if (!$app.arraysMatch(ref[prop], $ref[prop])) { - props[prop] = true; - } - } else if (ref[prop] !== Object(ref[prop])) { - props[prop] = true; - } - } - var has = false; - for (var prop in props) { - var asis = $ref[prop]; - var tobe = ref[prop]; - if (asis === tobe) { - delete props[prop]; - } else { - has = true; - props[prop] = [tobe, asis]; - } - } - if ($ref.note !== null && $ref.note !== ref.note) { - userNotes.checkNote(ref.id, ref.note); - } - // FIXME - // if the status is offline, just ignore status and statusDescription only. - if (has && ref.status !== 'offline' && $ref.status !== 'offline') { - if (props.location && props.location[0] !== 'traveling') { - var ts = Date.now(); - props.location.push(ts - ref.$location_at); - ref.$location_at = ts; - } - API.$emit('USER:UPDATE', { - ref, - props - }); - if ($app.debugUserDiff) { - delete props.last_login; - delete props.last_activity; - if (Object.keys(props).length !== 0) { - console.log('>', ref.displayName, props); - } - } - } - } - if ( - ref.$isVRCPlus && - ref.badges && - ref.badges.every( - (x) => x.badgeId !== 'bdg_754f9935-0f97-49d8-b857-95afb9b673fa' - ) - ) { - // I doubt this will last long - ref.badges.unshift({ - badgeId: 'bdg_754f9935-0f97-49d8-b857-95afb9b673fa', - badgeName: 'Supporter', - badgeDescription: 'Supports VRChat through VRC+', - badgeImageUrl: - 'https://assets.vrchat.com/badges/fa/bdgai_8c9cf371-ffd2-4177-9894-1093e2e34bf7.png', - hidden: true, - showcased: false - }); - } - var friendCtx = $app.friends.get(ref.id); - if (friendCtx) { - friendCtx.ref = ref; - friendCtx.name = ref.displayName; - } - if (ref.id === this.currentUser.id) { - if (ref.status) { - this.currentUser.status = ref.status; - } - $app.updateCurrentUserLocation(); - } - this.$emit('USER:APPLY', ref); - return ref; - }; - - // #endregion - // #region | API: World - - API.cachedWorlds = new Map(); - - API.$on('WORLD', function (args) { - args.ref = this.applyWorld(args.json); - }); - - API.$on('WORLD:LIST', function (args) { - for (var json of args.json) { - this.$emit('WORLD', { - json, - params: { - worldId: json.id - } - }); - } - }); - - API.$on('WORLD:DELETE', function (args) { - var { json } = args; - this.cachedWorlds.delete(json.id); - if ($app.worldDialog.ref.authorId === json.authorId) { - var map = new Map(); - for (var ref of this.cachedWorlds.values()) { - if (ref.authorId === json.authorId) { - map.set(ref.id, ref); - } - } - var array = Array.from(map.values()); - $app.userDialog.worlds = array; - } - }); - - API.$on('WORLD:SAVE', function (args) { - var { json } = args; - this.$emit('WORLD', { - json, - params: { - worldId: json.id - } - }); - }); - - API.getUserApiCurrentLocation = function () { - return this.currentUser?.presence?.world; - }; - - API.actuallyGetCurrentLocation = async function () { - let gameLogLocation = $app.lastLocation.location; - if (gameLogLocation.startsWith('local')) { - console.warn('PWI: local test mode', 'test_world'); - return 'test_world'; - } - if (gameLogLocation === 'traveling') { - gameLogLocation = $app.lastLocationDestination; - } - - let presenceLocation = this.currentUser.$locationTag; - if (presenceLocation === 'traveling') { - presenceLocation = this.currentUser.$travelingToLocation; - } - - // We want to use presence if it's valid to avoid extra API calls, but its prone to being outdated when this function is called. - // So we check if the presence location is the same as the gameLog location; If it is, the presence is (probably) valid and we can use it. - // If it's not, we need to get the user manually to get the correct location. - // If the user happens to be offline or the api is just being dumb, we assume that the user logged into VRCX is different than the one in-game and return the gameLog location. - // This is really dumb. - if (presenceLocation === gameLogLocation) { - const L = parseLocation(presenceLocation); - return L.worldId; - } - - const args = await userRequest.getUser({ userId: this.currentUser.id }); - const user = args.json; - let userLocation = user.location; - if (userLocation === 'traveling') { - userLocation = user.travelingToLocation; - } - console.warn( - "PWI: location didn't match, fetched user location", - userLocation - ); - - if (isRealInstance(userLocation)) { - console.warn('PWI: returning user location', userLocation); - const L = parseLocation(userLocation); - return L.worldId; - } - - if (isRealInstance(gameLogLocation)) { - console.warn(`PWI: returning gamelog location: `, gameLogLocation); - const L = parseLocation(gameLogLocation); - return L.worldId; - } - - console.error( - `PWI: all locations invalid: `, - gameLogLocation, - userLocation - ); - return 'test_world'; - }; - - API.applyWorld = function (json) { - var ref = this.cachedWorlds.get(json.id); - if (typeof ref === 'undefined') { - ref = { - id: '', - name: '', - description: '', - defaultContentSettings: {}, - authorId: '', - authorName: '', - capacity: 0, - recommendedCapacity: 0, - tags: [], - releaseStatus: '', - imageUrl: '', - thumbnailImageUrl: '', - assetUrl: '', - assetUrlObject: {}, - pluginUrl: '', - pluginUrlObject: {}, - unityPackageUrl: '', - unityPackageUrlObject: {}, - unityPackages: [], - version: 0, - favorites: 0, - created_at: '', - updated_at: '', - publicationDate: '', - labsPublicationDate: '', - visits: 0, - popularity: 0, - heat: 0, - publicOccupants: 0, - privateOccupants: 0, - occupants: 0, - instances: [], - featured: false, - organization: '', - previewYoutubeId: '', - // VRCX - $isLabs: false, - // - ...json - }; - this.cachedWorlds.set(ref.id, ref); - } else { - Object.assign(ref, json); - } - ref.$isLabs = ref.tags.includes('system_labs'); - ref.name = $utils.replaceBioSymbols(ref.name); - ref.description = $utils.replaceBioSymbols(ref.description); - return ref; - }; - - // #endregion - // #region | API: Instance - - API.cachedInstances = new Map(); - - API.applyInstance = function (json) { - var ref = this.cachedInstances.get(json.id); - if (typeof ref === 'undefined') { - ref = { - id: '', - location: '', - instanceId: '', - name: '', - worldId: '', - type: '', - ownerId: '', - tags: [], - active: false, - full: false, - n_users: 0, - hasCapacityForYou: true, // not present depending on endpoint - capacity: 0, - recommendedCapacity: 0, - userCount: 0, - queueEnabled: false, // only present with group instance type - queueSize: 0, // only present when queuing is enabled - platforms: {}, - gameServerVersion: 0, - hardClose: null, // boolean or null - closedAt: null, // string or null - secureName: '', - shortName: '', - world: {}, - users: [], // only present when you're the owner - clientNumber: '', - contentSettings: {}, - photonRegion: '', - region: '', - canRequestInvite: false, - permanent: false, - private: '', // part of instance tag - hidden: '', // part of instance tag - nonce: '', // only present when you're the owner - strict: false, // deprecated - displayName: null, - groupAccessType: null, // only present with group instance type - roleRestricted: false, // only present with group instance type - instancePersistenceEnabled: null, - playerPersistenceEnabled: null, - ageGate: null, - // VRCX - $fetchedAt: '', - $disabledContentSettings: [], - ...json - }; - this.cachedInstances.set(ref.id, ref); - } else { - Object.assign(ref, json); - } - ref.$location = parseLocation(ref.location); - if (json.world?.id) { - worldRequest - .getCachedWorld({ - worldId: json.world.id - }) - .then((args) => { - ref.world = args.ref; - return args; - }); - } - if (!json.$fetchedAt) { - ref.$fetchedAt = new Date().toJSON(); - } - ref.$disabledContentSettings = []; - if (json.contentSettings && Object.keys(json.contentSettings).length) { - for (var setting of $app.instanceContentSettings) { - if ( - typeof json.contentSettings[setting] === 'undefined' || - json.contentSettings[setting] === true - ) { - continue; - } - ref.$disabledContentSettings.push(setting); - } - } - return ref; - }; - - API.$on('INSTANCE', function (args) { - var { json } = args; - if (!json) { - return; - } - args.ref = this.applyInstance(args.json); - }); - - API.$on('INSTANCE', function (args) { - if (!args.json?.id) { - return; - } - if ( - $app.userDialog.visible && - $app.userDialog.ref.$location.tag === args.json.id - ) { - $app.applyUserDialogLocation(); - } - if ( - $app.worldDialog.visible && - $app.worldDialog.id === args.json.worldId - ) { - $app.applyWorldDialogInstances(); - } - if ( - $app.groupDialog.visible && - $app.groupDialog.id === args.json.ownerId - ) { - $app.applyGroupDialogInstances(); - } - - // FIXME: - // because use $refs to update data, can not trigger vue's reactivity system, so view will not update - // will fix this when refactor the core code, maybe - // old comment: hacky workaround to force update instance info - $app.updateInstanceInfo++; - }); - - // #endregion - // #region | API: Friend - - API.$on('FRIEND:LIST', function (args) { - for (var json of args.json) { - if (!json.displayName) { - console.error('/friends gave us garbage', json); - continue; - } - this.$emit('USER', { - json, - params: { - userId: json.id - } - }); - } - }); - - API.isRefreshFriendsLoading = false; - - API.refreshFriends = async function () { - this.isRefreshFriendsLoading = true; - try { - var onlineFriends = await this.bulkRefreshFriends({ - offline: false - }); - var offlineFriends = await this.bulkRefreshFriends({ - offline: true - }); - var friends = onlineFriends.concat(offlineFriends); - friends = await this.refetchBrokenFriends(friends); - if (!$app.friendLogInitStatus) { - friends = await this.refreshRemainingFriends(friends); - } - - this.isRefreshFriendsLoading = false; - return friends; - } catch (err) { - this.isRefreshFriendsLoading = false; - throw err; - } - }; - - API.bulkRefreshFriends = async function (params) { - var friends = []; - var params = { - ...params, - n: 50, - offset: 0 - }; - // API offset limit *was* 5000 - // it is now 7500 - mainLoop: for (var i = 150; i > -1; i--) { - retryLoop: for (var j = 0; j < 10; j++) { - // handle 429 ratelimit error, retry 10 times - try { - var args = await friendRequest.getFriends(params); - if (!args.json || args.json.length === 0) { - break mainLoop; - } - friends = friends.concat(args.json); - break retryLoop; - } catch (err) { - console.error(err); - if (!API.currentUser.isLoggedIn) { - console.error(`User isn't logged in`); - break mainLoop; - } - if (err?.message?.includes('Not Found')) { - console.error('Awful workaround for awful VRC API bug'); - break retryLoop; - } - await new Promise((resolve) => { - workerTimers.setTimeout(resolve, 5000); - }); - } - } - params.offset += 50; - } - return friends; - }; - - API.refreshRemainingFriends = async function (friends) { - for (var userId of this.currentUser.friends) { - if (!friends.some((x) => x.id === userId)) { - try { - if (!API.isLoggedIn) { - console.error(`User isn't logged in`); - return friends; - } - console.log('Fetching remaining friend', userId); - var args = await userRequest.getUser({ userId }); - friends.push(args.json); - } catch (err) { - console.error(err); - } - } - } - return friends; - }; - - API.refetchBrokenFriends = async function (friends) { - // attempt to fix broken data from bulk friend fetch - for (var i = 0; i < friends.length; i++) { - var friend = friends[i]; - try { - // we don't update friend state here, it's not reliable - var state = 'offline'; - if (friend.platform === 'web') { - state = 'active'; - } else if (friend.platform) { - state = 'online'; - } - var ref = $app.friends.get(friend.id); - if (ref?.state !== state) { - if ($app.debugFriendState) { - console.log( - `Refetching friend state it does not match ${friend.displayName} from ${ref?.state} to ${state}`, - friend - ); - } - var args = await userRequest.getUser({ - userId: friend.id - }); - friends[i] = args.json; - } else if (friend.location === 'traveling') { - if ($app.debugFriendState) { - console.log( - 'Refetching traveling friend', - friend.displayName - ); - } - var args = await userRequest.getUser({ - userId: friend.id - }); - friends[i] = args.json; - } - } catch (err) { - console.error(err); - } - } - return friends; - }; - - // #endregion - // #region | API: Avatar - - API.cachedAvatars = new Map(); - - API.$on('AVATAR', function (args) { - args.ref = this.applyAvatar(args.json); - }); - - API.$on('AVATAR:LIST', function (args) { - for (var json of args.json) { - this.$emit('AVATAR', { - json, - params: { - avatarId: json.id - } - }); - } - }); - - API.$on('AVATAR:SAVE', function (args) { - var { json } = args; - this.$emit('AVATAR', { - json, - params: { - avatarId: json.id - } - }); - }); - - API.$on('AVATAR:SELECT', function (args) { - this.$emit('USER:CURRENT', args); - }); - - API.$on('AVATAR:DELETE', function (args) { - var { json } = args; - this.cachedAvatars.delete(json._id); - if ($app.userDialog.id === json.authorId) { - var map = new Map(); - for (var ref of this.cachedAvatars.values()) { - if (ref.authorId === json.authorId) { - map.set(ref.id, ref); - } - } - var array = Array.from(map.values()); - $app.sortUserDialogAvatars(array); - } - }); - - API.applyAvatar = function (json) { - var ref = this.cachedAvatars.get(json.id); - if (typeof ref === 'undefined') { - ref = { - acknowledgements: '', - authorId: '', - authorName: '', - created_at: '', - description: '', - featured: false, - highestPrice: null, - id: '', - imageUrl: '', - lock: false, - lowestPrice: null, - name: '', - productId: null, - publishedListings: [], - releaseStatus: '', - searchable: false, - styles: [], - tags: [], - thumbnailImageUrl: '', - unityPackageUrl: '', - unityPackageUrlObject: {}, - unityPackages: [], - updated_at: '', - version: 0, - ...json - }; - this.cachedAvatars.set(ref.id, ref); - } else { - var { unityPackages } = ref; - Object.assign(ref, json); - if ( - json.unityPackages?.length > 0 && - unityPackages.length > 0 && - !json.unityPackages[0].assetUrl - ) { - ref.unityPackages = unityPackages; - } - } - for (const listing of ref?.publishedListings) { - listing.displayName = $utils.replaceBioSymbols(listing.displayName); - listing.description = $utils.replaceBioSymbols(listing.description); - } - ref.name = $utils.replaceBioSymbols(ref.name); - ref.description = $utils.replaceBioSymbols(ref.description); - return ref; - }; - - // API.$on('AVATAR:IMPOSTER:DELETE', function (args) { - // if ( - // $app.avatarDialog.visible && - // args.params.avatarId === $app.avatarDialog.id - // ) { - // $app.showAvatarDialog($app.avatarDialog.id); - // } - // }); - - // #endregion - // #region | API: Notification - - API.isNotificationsLoading = false; - - API.$on('LOGIN', function () { - this.isNotificationsLoading = false; - }); - - API.$on('NOTIFICATION', function (args) { - args.ref = this.applyNotification(args.json); - }); - - API.$on('NOTIFICATION:LIST', function (args) { - for (var json of args.json) { - this.$emit('NOTIFICATION', { - json, - params: { - notificationId: json.id - } - }); - } - }); - - API.$on('NOTIFICATION:LIST:HIDDEN', function (args) { - for (var json of args.json) { - json.type = 'ignoredFriendRequest'; - this.$emit('NOTIFICATION', { - json, - params: { - notificationId: json.id - } - }); - } - }); - - API.$on('NOTIFICATION:ACCEPT', function (args) { - var array = $app.notificationTable.data; - for (var i = array.length - 1; i >= 0; i--) { - if (array[i].id === args.params.notificationId) { - var ref = array[i]; - break; - } - } - if (typeof ref === 'undefined') { - return; - } - ref.$isExpired = true; - args.ref = ref; - this.$emit('NOTIFICATION:EXPIRE', { - ref, - params: { - notificationId: ref.id - } - }); - this.$emit('FRIEND:ADD', { - params: { - userId: ref.senderUserId - } - }); - }); - - API.$on('NOTIFICATION:HIDE', function (args) { - var array = $app.notificationTable.data; - for (var i = array.length - 1; i >= 0; i--) { - if (array[i].id === args.params.notificationId) { - var ref = array[i]; - break; - } - } - if (typeof ref === 'undefined') { - return; - } - args.ref = ref; - if ( - ref.type === 'friendRequest' || - ref.type === 'ignoredFriendRequest' || - ref.type.includes('.') - ) { - for (var i = array.length - 1; i >= 0; i--) { - if (array[i].id === ref.id) { - array.splice(i, 1); - break; - } - } - } else { - ref.$isExpired = true; - database.updateNotificationExpired(ref); - } - this.$emit('NOTIFICATION:EXPIRE', { - ref, - params: { - notificationId: ref.id - } - }); - }); - - API.applyNotification = function (json) { - var array = $app.notificationTable.data; - for (var i = array.length - 1; i >= 0; i--) { - if (array[i].id === json.id) { - var ref = array[i]; - break; - } - } - // delete any null in json - for (var key in json) { - if (json[key] === null) { - delete json[key]; - } - } - if (typeof ref === 'undefined') { - ref = { - id: '', - senderUserId: '', - senderUsername: '', - type: '', - message: '', - details: {}, - seen: false, - created_at: '', - // VRCX - $isExpired: false, - // - ...json - }; - } else { - Object.assign(ref, json); - ref.$isExpired = false; - } - if (ref.details !== Object(ref.details)) { - var details = {}; - if (ref.details !== '{}') { - try { - var object = JSON.parse(ref.details); - if (object === Object(object)) { - details = object; - } - } catch (err) {} - } - ref.details = details; - } - return ref; - }; - - API.expireFriendRequestNotifications = function () { - var array = $app.notificationTable.data; - for (var i = array.length - 1; i >= 0; i--) { - if ( - array[i].type === 'friendRequest' || - array[i].type === 'ignoredFriendRequest' || - array[i].type.includes('.') - ) { - array.splice(i, 1); - } - } - }; - - API.expireNotification = function (notificationId) { - var array = $app.notificationTable.data; - for (var i = array.length - 1; i >= 0; i--) { - if (array[i].id === notificationId) { - var ref = array[i]; - break; - } - } - if (typeof ref === 'undefined') { - return; - } - ref.$isExpired = true; - database.updateNotificationExpired(ref); - this.$emit('NOTIFICATION:EXPIRE', { - ref, - params: { - notificationId: ref.id - } - }); - }; - - API.refreshNotifications = async function () { - this.isNotificationsLoading = true; - try { - this.expireFriendRequestNotifications(); - var params = { - n: 100, - offset: 0 - }; - var count = 50; // 5000 max - for (var i = 0; i < count; i++) { - var args = await notificationRequest.getNotifications(params); - $app.unseenNotifications = []; - params.offset += 100; - if (args.json.length < 100) { - break; - } - } - var params = { - n: 100, - offset: 0 - }; - var count = 50; // 5000 max - for (var i = 0; i < count; i++) { - var args = await notificationRequest.getNotificationsV2(params); - $app.unseenNotifications = []; - params.offset += 100; - if (args.json.length < 100) { - break; - } - } - var params = { - n: 100, - offset: 0 - }; - var count = 50; // 5000 max - for (var i = 0; i < count; i++) { - var args = - await notificationRequest.getHiddenFriendRequests(params); - $app.unseenNotifications = []; - params.offset += 100; - if (args.json.length < 100) { - break; - } - } - } catch (err) { - console.error(err); - } finally { - this.isNotificationsLoading = false; - $app.notificationInitStatus = true; - } - }; - - API.$on('NOTIFICATION:V2:LIST', function (args) { - for (var json of args.json) { - this.$emit('NOTIFICATION:V2', { json }); - } - }); - - API.$on('NOTIFICATION:V2', function (args) { - var json = args.json; - json.created_at = json.createdAt; - if (json.title && json.message) { - json.message = `${json.title}, ${json.message}`; - } else if (json.title) { - json.message = json.title; - } - this.$emit('NOTIFICATION', { - json, - params: { - notificationId: json.id - } - }); - }); - - API.$on('NOTIFICATION:V2:UPDATE', function (args) { - var notificationId = args.params.notificationId; - var json = args.json; - if (!json) { - return; - } - json.id = notificationId; - this.$emit('NOTIFICATION', { - json, - params: { - notificationId - } - }); - if (json.seen) { - this.$emit('NOTIFICATION:SEE', { - params: { - notificationId - } - }); - } - }); - - API.$on('NOTIFICATION:RESPONSE', function (args) { - this.$emit('NOTIFICATION:HIDE', args); - new Noty({ - type: 'success', - text: $app.escapeTag(args.json) - }).show(); - console.log('NOTIFICATION:RESPONSE', args); - }); - - API.getFriendRequest = function (userId) { - var array = $app.notificationTable.data; - for (var i = array.length - 1; i >= 0; i--) { - if ( - array[i].type === 'friendRequest' && - array[i].senderUserId === userId - ) { - return array[i].id; - } - } - return ''; - }; - - // #endregion - // #region | API: PlayerModeration - - API.cachedPlayerModerations = new Map(); - API.cachedPlayerModerationsUserIds = new Set(); - API.isPlayerModerationsLoading = false; - - API.$on('LOGIN', function () { - this.cachedPlayerModerations.clear(); - this.cachedPlayerModerationsUserIds.clear(); - this.isPlayerModerationsLoading = false; - this.refreshPlayerModerations(); - }); - - API.$on('PLAYER-MODERATION', function (args) { - args.ref = this.applyPlayerModeration(args.json); - }); - - API.$on('PLAYER-MODERATION:LIST', function (args) { - for (var json of args.json) { - this.$emit('PLAYER-MODERATION', { - json, - params: { - playerModerationId: json.id - } - }); - } - }); - - API.$on('PLAYER-MODERATION:SEND', function (args) { - var ref = { - json: args.json, - params: { - playerModerationId: args.json.id - } - }; - this.$emit('PLAYER-MODERATION', ref); - this.$emit('PLAYER-MODERATION:@SEND', ref); - }); - - API.$on('PLAYER-MODERATION:DELETE', function (args) { - var { type, moderated } = args.params; - var userId = this.currentUser.id; - for (var ref of this.cachedPlayerModerations.values()) { - if ( - ref.type === type && - ref.targetUserId === moderated && - ref.sourceUserId === userId - ) { - this.cachedPlayerModerations.delete(ref.id); - this.$emit('PLAYER-MODERATION:@DELETE', { - ref, - params: { - playerModerationId: ref.id - } - }); - } - } - this.cachedPlayerModerationsUserIds.delete(moderated); - }); - - API.applyPlayerModeration = function (json) { - var ref = this.cachedPlayerModerations.get(json.id); - if (typeof ref === 'undefined') { - ref = { - id: '', - type: '', - sourceUserId: '', - sourceDisplayName: '', - targetUserId: '', - targetDisplayName: '', - created: '', - // VRCX - $isExpired: false, - // - ...json - }; - this.cachedPlayerModerations.set(ref.id, ref); - } else { - Object.assign(ref, json); - ref.$isExpired = false; - } - if (json.targetUserId) { - this.cachedPlayerModerationsUserIds.add(json.targetUserId); - } - return ref; - }; - - API.expirePlayerModerations = function () { - this.cachedPlayerModerationsUserIds.clear(); - for (var ref of this.cachedPlayerModerations.values()) { - ref.$isExpired = true; - } - }; - - API.deleteExpiredPlayerModerations = function () { - for (var ref of this.cachedPlayerModerations.values()) { - if (!ref.$isExpired) { - continue; - } - this.$emit('PLAYER-MODERATION:@DELETE', { - ref, - params: { - playerModerationId: ref.id - } - }); - } - }; - - API.refreshPlayerModerations = function () { - if (this.isPlayerModerationsLoading) { - return; - } - this.isPlayerModerationsLoading = true; - this.expirePlayerModerations(); - Promise.all([ - playerModerationRequest.getPlayerModerations(), - avatarModerationRequest.getAvatarModerations() - ]) - .finally(() => { - this.isPlayerModerationsLoading = false; - }) - .then((res) => { - // 'AVATAR-MODERATION:LIST'; - // TODO: compare with cachedAvatarModerations - this.cachedAvatarModerations = new Map(); - for (var json of res[1]?.json) { - this.applyAvatarModeration(json); - } - this.deleteExpiredPlayerModerations(); - }); - }; - - // #endregion - // #region | API: AvatarModeration - - API.cachedAvatarModerations = new Map(); - - API.applyAvatarModeration = function (json) { - // fix inconsistent Unix time response - if (typeof json.created === 'number') { - json.created = new Date(json.created).toJSON(); - } - - var ref = this.cachedAvatarModerations.get(json.targetAvatarId); - if (typeof ref === 'undefined') { - ref = { - avatarModerationType: '', - created: '', - targetAvatarId: '', - ...json - }; - this.cachedAvatarModerations.set(ref.targetAvatarId, ref); - } else { - Object.assign(ref, json); - } - - // update avatar dialog - var D = $app.avatarDialog; - if ( - D.visible && - ref.avatarModerationType === 'block' && - D.id === ref.targetAvatarId - ) { - D.isBlocked = true; - } - - return ref; - }; - - // #endregion - // #region | API: Favorite - - API.cachedFavorites = new Map(); - API.cachedFavoritesByObjectId = new Map(); - API.cachedFavoriteGroups = new Map(); - API.cachedFavoriteGroupsByTypeName = new Map(); - API.favoriteFriendGroups = []; - API.favoriteWorldGroups = []; - API.favoriteAvatarGroups = []; - API.isFavoriteLoading = false; - API.isFavoriteGroupLoading = false; - API.favoriteLimits = { - maxFavoriteGroups: { - avatar: 6, - friend: 3, - world: 4 - }, - maxFavoritesPerGroup: { - avatar: 50, - friend: 150, - world: 100 - } - }; - - API.$on('LOGIN', function () { - $app.localFavoriteFriends.clear(); - $app.currentUserGroupsInit = false; - this.cachedGroups.clear(); - this.cachedAvatars.clear(); - this.cachedWorlds.clear(); - this.cachedUsers.clear(); - this.cachedInstances.clear(); - this.cachedAvatarNames.clear(); - this.cachedAvatarModerations.clear(); - this.cachedPlayerModerations.clear(); - this.cachedFavorites.clear(); - this.cachedFavoritesByObjectId.clear(); - this.cachedFavoriteGroups.clear(); - this.cachedFavoriteGroupsByTypeName.clear(); - this.currentUserGroups.clear(); - this.currentUserInventory.clear(); - this.queuedInstances.clear(); - this.favoriteFriendGroups = []; - this.favoriteWorldGroups = []; - this.favoriteAvatarGroups = []; - this.isFavoriteLoading = false; - this.isFavoriteGroupLoading = false; - this.refreshFavorites(); - }); - - API.$on('FAVORITE', function (args) { - var ref = this.applyFavorite(args.json); - if (ref.$isDeleted) { - return; - } - args.ref = ref; - }); - - API.$on('FAVORITE:@DELETE', function (args) { - var { ref } = args; - if (ref.$groupRef !== null) { - --ref.$groupRef.count; - } - }); - - API.$on('FAVORITE:LIST', function (args) { - for (var json of args.json) { - this.$emit('FAVORITE', { - json, - params: { - favoriteId: json.id - }, - sortTop: false - }); - } - }); - - API.$on('FAVORITE:ADD', function (args) { - this.$emit('FAVORITE', { - json: args.json, - params: { - favoriteId: args.json.id - }, - sortTop: true - }); - }); - - API.$on('FAVORITE:ADD', function (args) { - if ( - args.params.type === 'avatar' && - !API.cachedAvatars.has(args.params.favoriteId) - ) { - this.refreshFavoriteAvatars(args.params.tags); - } - - if ( - args.params.type === 'friend' && - $app.localFavoriteFriendsGroups.includes( - 'friend:' + args.params.tags - ) - ) { - $app.updateLocalFavoriteFriends(); - } - }); - - API.$on('FAVORITE:DELETE', function (args) { - var ref = this.cachedFavoritesByObjectId.get(args.params.objectId); - if (typeof ref === 'undefined') { - return; - } - // 애초에 $isDeleted인데 여기로 올 수 가 있나..? - this.cachedFavoritesByObjectId.delete(args.params.objectId); - $app.localFavoriteFriends.delete(args.params.objectId); - $app.updateSidebarFriendsList(); - if (ref.$isDeleted) { - return; - } - args.ref = ref; - ref.$isDeleted = true; - API.$emit('FAVORITE:@DELETE', { - ref, - params: { - favoriteId: ref.id - } - }); - }); - - API.$on('FAVORITE:GROUP', function (args) { - var ref = this.applyFavoriteGroup(args.json); - if (ref.$isDeleted) { - return; - } - args.ref = ref; - if (ref.$groupRef !== null) { - ref.$groupRef.displayName = ref.displayName; - ref.$groupRef.visibility = ref.visibility; - } - }); - - API.$on('FAVORITE:GROUP:LIST', function (args) { - for (var json of args.json) { - this.$emit('FAVORITE:GROUP', { - json, - params: { - favoriteGroupId: json.id - } - }); - } - }); - - API.$on('FAVORITE:GROUP:SAVE', function (args) { - this.$emit('FAVORITE:GROUP', { - json: args.json, - params: { - favoriteGroupId: args.json.id - } - }); - }); - - API.$on('FAVORITE:GROUP:CLEAR', function (args) { - var key = `${args.params.type}:${args.params.group}`; - for (var ref of this.cachedFavorites.values()) { - if (ref.$isDeleted || ref.$groupKey !== key) { - continue; - } - this.cachedFavoritesByObjectId.delete(ref.favoriteId); - $app.localFavoriteFriends.delete(ref.favoriteId); - $app.updateSidebarFriendsList(); - ref.$isDeleted = true; - API.$emit('FAVORITE:@DELETE', { - ref, - params: { - favoriteId: ref.id - } - }); - } - }); - - API.$on('FAVORITE:WORLD:LIST', function (args) { - for (var json of args.json) { - if (json.id === '???') { - // FIXME - // json.favoriteId로 따로 불러와야 하나? - // 근데 ???가 많으면 과다 요청이 될듯 - continue; - } - this.$emit('WORLD', { - json, - params: { - worldId: json.id - } - }); - } - }); - - API.$on('FAVORITE:AVATAR:LIST', function (args) { - for (var json of args.json) { - if (json.releaseStatus === 'hidden') { - // NOTE: 얘는 또 더미 데이터로 옴 - continue; - } - this.$emit('AVATAR', { - json, - params: { - avatarId: json.id - } - }); - } - }); - - API.applyFavorite = function (json) { - var ref = this.cachedFavorites.get(json.id); - if (typeof ref === 'undefined') { - ref = { - id: '', - type: '', - favoriteId: '', - tags: [], - // VRCX - $isDeleted: false, - $isExpired: false, - $groupKey: '', - $groupRef: null, - // - ...json - }; - this.cachedFavorites.set(ref.id, ref); - this.cachedFavoritesByObjectId.set(ref.favoriteId, ref); - if ( - ref.type === 'friend' && - ($app.localFavoriteFriendsGroups.length === 0 || - $app.localFavoriteFriendsGroups.includes(ref.groupKey)) - ) { - $app.localFavoriteFriends.add(ref.favoriteId); - $app.updateSidebarFriendsList(); - } - } else { - Object.assign(ref, json); - ref.$isExpired = false; - } - ref.$groupKey = `${ref.type}:${String(ref.tags[0])}`; - - if (ref.$isDeleted === false && ref.$groupRef === null) { - var group = this.cachedFavoriteGroupsByTypeName.get(ref.$groupKey); - if (typeof group !== 'undefined') { - ref.$groupRef = group; - ++group.count; - } - } - return ref; - }; - - API.expireFavorites = function () { - $app.localFavoriteFriends.clear(); - this.cachedFavorites.clear(); - this.cachedFavoritesByObjectId.clear(); - $app.favoriteObjects.clear(); - $app.favoriteFriends_ = []; - $app.favoriteFriendsSorted = []; - $app.favoriteWorlds_ = []; - $app.favoriteWorldsSorted = []; - $app.favoriteAvatars_ = []; - $app.favoriteAvatarsSorted = []; - }; - - API.deleteExpiredFavorites = function () { - for (var ref of this.cachedFavorites.values()) { - if (ref.$isDeleted || ref.$isExpired === false) { - continue; - } - ref.$isDeleted = true; - this.$emit('FAVORITE:@DELETE', { - ref, - params: { - favoriteId: ref.id - } - }); - } - }; - - API.refreshFavoriteAvatars = function (tag) { - var n = Math.floor(Math.random() * (50 + 1)) + 50; - var params = { - n, - offset: 0, - tag - }; - favoriteRequest.getFavoriteAvatars(params); - }; - - API.refreshFavoriteItems = function () { - var types = { - world: [0, favoriteRequest.getFavoriteWorlds], - avatar: [0, favoriteRequest.getFavoriteAvatars] - }; - var tags = []; - for (var ref of this.cachedFavorites.values()) { - if (ref.$isDeleted) { - continue; - } - var type = types[ref.type]; - if (typeof type === 'undefined') { - continue; - } - if (ref.type === 'avatar' && !tags.includes(ref.tags[0])) { - tags.push(ref.tags[0]); - } - ++type[0]; - } - for (var type in types) { - var [N, fn] = types[type]; - if (N > 0) { - if (type === 'avatar') { - for (var tag of tags) { - var n = Math.floor(Math.random() * (50 + 1)) + 50; - this.bulk({ - fn, - N, - params: { - n, - offset: 0, - tag - } - }); - } - } else { - var n = Math.floor(Math.random() * (36 + 1)) + 64; - this.bulk({ - fn, - N, - params: { - n, - offset: 0 - } - }); - } - } - } - }; - - API.refreshFavorites = async function () { - if (this.isFavoriteLoading) { - return; - } - this.isFavoriteLoading = true; - try { - await favoriteRequest.getFavoriteLimits(); - } catch (err) { - console.error(err); - } - this.expireFavorites(); - this.cachedFavoriteGroupsByTypeName.clear(); - this.bulk({ - fn: favoriteRequest.getFavorites, - N: -1, - params: { - n: 50, - offset: 0 - }, - done(ok) { - if (ok) { - this.deleteExpiredFavorites(); - } - this.refreshFavoriteItems(); - this.refreshFavoriteGroups(); - $app.updateLocalFavoriteFriends(); - this.isFavoriteLoading = false; - } - }); - }; - - API.applyFavoriteGroup = function (json) { - var ref = this.cachedFavoriteGroups.get(json.id); - if (typeof ref === 'undefined') { - ref = { - id: '', - ownerId: '', - ownerDisplayName: '', - name: '', - displayName: '', - type: '', - visibility: '', - tags: [], - // VRCX - $isDeleted: false, - $isExpired: false, - $groupRef: null, - // - ...json - }; - this.cachedFavoriteGroups.set(ref.id, ref); - } else { - Object.assign(ref, json); - ref.$isExpired = false; - } - return ref; - }; - - API.buildFavoriteGroups = function () { - // 450 = ['group_0', 'group_1', 'group_2'] x 150 - this.favoriteFriendGroups = []; - for (var i = 0; i < this.favoriteLimits.maxFavoriteGroups.friend; ++i) { - this.favoriteFriendGroups.push({ - assign: false, - key: `friend:group_${i}`, - type: 'friend', - name: `group_${i}`, - displayName: `Group ${i + 1}`, - capacity: this.favoriteLimits.maxFavoritesPerGroup.friend, - count: 0, - visibility: 'private' - }); - } - // 400 = ['worlds1', 'worlds2', 'worlds3', 'worlds4'] x 100 - this.favoriteWorldGroups = []; - for (var i = 0; i < this.favoriteLimits.maxFavoriteGroups.world; ++i) { - this.favoriteWorldGroups.push({ - assign: false, - key: `world:worlds${i + 1}`, - type: 'world', - name: `worlds${i + 1}`, - displayName: `Group ${i + 1}`, - capacity: this.favoriteLimits.maxFavoritesPerGroup.world, - count: 0, - visibility: 'private' - }); - } - // 350 = ['avatars1', ...] x 50 - // Favorite Avatars (0/50) - // VRC+ Group 1..5 (0/50) - this.favoriteAvatarGroups = []; - for (var i = 0; i < this.favoriteLimits.maxFavoriteGroups.avatar; ++i) { - this.favoriteAvatarGroups.push({ - assign: false, - key: `avatar:avatars${i + 1}`, - type: 'avatar', - name: `avatars${i + 1}`, - displayName: `Group ${i + 1}`, - capacity: this.favoriteLimits.maxFavoritesPerGroup.avatar, - count: 0, - visibility: 'private' - }); - } - var types = { - friend: this.favoriteFriendGroups, - world: this.favoriteWorldGroups, - avatar: this.favoriteAvatarGroups - }; - var assigns = new Set(); - // assign the same name first - for (var ref of this.cachedFavoriteGroups.values()) { - if (ref.$isDeleted) { - continue; - } - var groups = types[ref.type]; - if (typeof groups === 'undefined') { - continue; - } - for (var group of groups) { - if (group.assign === false && group.name === ref.name) { - group.assign = true; - if (ref.displayName) { - group.displayName = ref.displayName; - } - group.visibility = ref.visibility; - ref.$groupRef = group; - assigns.add(ref.id); - break; - } - } - } - // assign the rest - // FIXME - // The order (cachedFavoriteGroups) is very important. It should be - // processed in the order in which the server responded. But since we - // used Map(), the order would be a mess. So we need something to solve - // this. - for (var ref of this.cachedFavoriteGroups.values()) { - if (ref.$isDeleted || assigns.has(ref.id)) { - continue; - } - var groups = types[ref.type]; - if (typeof groups === 'undefined') { - continue; - } - for (var group of groups) { - if (group.assign === false) { - group.assign = true; - group.key = `${group.type}:${ref.name}`; - group.name = ref.name; - group.displayName = ref.displayName; - ref.$groupRef = group; - assigns.add(ref.id); - break; - } - } - } - // update favorites - this.cachedFavoriteGroupsByTypeName.clear(); - for (var type in types) { - for (var group of types[type]) { - this.cachedFavoriteGroupsByTypeName.set(group.key, group); - } - } - for (var ref of this.cachedFavorites.values()) { - ref.$groupRef = null; - if (ref.$isDeleted) { - continue; - } - var group = this.cachedFavoriteGroupsByTypeName.get(ref.$groupKey); - if (typeof group === 'undefined') { - continue; - } - ref.$groupRef = group; - ++group.count; - } - }; - - API.expireFavoriteGroups = function () { - for (var ref of this.cachedFavoriteGroups.values()) { - ref.$isExpired = true; - } - }; - - API.deleteExpiredFavoriteGroups = function () { - for (var ref of this.cachedFavoriteGroups.values()) { - if (ref.$isDeleted || ref.$isExpired === false) { - continue; - } - ref.$isDeleted = true; - this.$emit('FAVORITE:GROUP:@DELETE', { - ref, - params: { - favoriteGroupId: ref.id - } - }); - } - }; - - API.$on('FAVORITE:LIMITS', function (args) { - this.favoriteLimits = { - ...this.favoriteLimits, - ...args.json - }; - }); - - API.refreshFavoriteGroups = function () { - if (this.isFavoriteGroupLoading) { - return; - } - this.isFavoriteGroupLoading = true; - this.expireFavoriteGroups(); - this.bulk({ - fn: favoriteRequest.getFavoriteGroups, - N: -1, - params: { - n: 50, - offset: 0 - }, - done(ok) { - if (ok) { - this.deleteExpiredFavoriteGroups(); - this.buildFavoriteGroups(); - } - this.isFavoriteGroupLoading = false; - } - }); - }; - - // #endregion - // #region | Misc - - var $timers = []; - - Vue.component('timer', { - template: '', - props: { - epoch: { - type: Number, - default() { - return Date.now(); - } - } - }, - data() { - return { - text: '' - }; - }, - methods: { - update() { - if (!this.epoch) { - this.text = '-'; - return; - } - this.text = $app.timeToText(Date.now() - this.epoch); - } - }, - watch: { - date() { - this.update(); - } - }, - mounted() { - $timers.push(this); - this.update(); - }, - destroyed() { - $app.removeFromArray($timers, this); - } - }); - - workerTimers.setInterval(function () { - for (var $timer of $timers) { - $timer.update(); - } - }, 5000); - - // Countdown timer - - var $countDownTimers = []; - - Vue.component('countdown-timer', { - template: '', - props: { - datetime: { - type: String, - default() { - return ''; - } - }, - hours: { - type: Number, - default() { - return 1; - } - } - }, - data() { - return { - text: '' - }; - }, - methods: { - update() { - var epoch = - new Date(this.datetime).getTime() + - 1000 * 60 * 60 * this.hours - - Date.now(); - if (epoch >= 0) { - this.text = $app.timeToText(epoch); - } else { - this.text = '-'; - } - } - }, - watch: { - date() { - this.update(); - } - }, - mounted() { - $countDownTimers.push(this); - this.update(); - }, - destroyed() { - $app.removeFromArray($countDownTimers, this); - } - }); - - workerTimers.setInterval(function () { - for (var $countDownTimer of $countDownTimers) { - $countDownTimer.update(); - } - }, 5000); - - // #endregion - // #region | initialise - - $app.methods.refreshCustomCss = function () { - if (document.contains(document.getElementById('app-custom-style'))) { - document.getElementById('app-custom-style').remove(); - } - AppApi.CustomCssPath().then((customCss) => { - var head = document.head; - if (customCss) { - var $appCustomStyle = document.createElement('link'); - $appCustomStyle.setAttribute('id', 'app-custom-style'); - $appCustomStyle.rel = 'stylesheet'; - $appCustomStyle.href = `file://${customCss}?_=${Date.now()}`; - head.appendChild($appCustomStyle); - } - }); - }; - - $app.methods.refreshCustomScript = function () { - if (document.contains(document.getElementById('app-custom-script'))) { - document.getElementById('app-custom-script').remove(); - } - AppApi.CustomScriptPath().then((customScript) => { - var head = document.head; - if (customScript) { - var $appCustomScript = document.createElement('script'); - $appCustomScript.setAttribute('id', 'app-custom-script'); - $appCustomScript.src = `file://${customScript}?_=${Date.now()}`; - head.appendChild($appCustomScript); - } - }); - }; - - $app.methods.openExternalLink = function (link) { - this.$confirm(`${link}`, 'Open External Link', { - distinguishCancelAndClose: true, - confirmButtonText: 'Open', - cancelButtonText: 'Copy', - type: 'info', - callback: (action) => { - if (action === 'confirm') { - AppApi.OpenLink(link); - } else if (action === 'cancel') { - this.copyLink(link); - } - } - }); - }; - - $app.methods.compareAppVersion = async function () { - if (!this.appVersion) { - return; - } - var currentVersion = this.appVersion.replace(' (Linux)', ''); - var lastVersion = await configRepository.getString( - 'VRCX_lastVRCXVersion', - '' - ); - if (!lastVersion) { - await configRepository.setString( - 'VRCX_lastVRCXVersion', - currentVersion - ); - return; - } - if (lastVersion !== currentVersion) { - await configRepository.setString( - 'VRCX_lastVRCXVersion', - currentVersion - ); - if ( - (await configRepository.getString('VRCX_branch')) === 'Stable' - ) { - this.showChangeLogDialog(); - } - } - }; - - $app.methods.setBranch = async function () { - if (!this.appVersion) { - return; - } - var currentVersion = this.appVersion.replace(' (Linux)', ''); - if (currentVersion.includes('VRCX Nightly')) { - this.branch = 'Nightly'; - } else { - this.branch = 'Stable'; - } - await configRepository.setString('VRCX_branch', this.branch); - }; - - $app.data.vrcxId = ''; - $app.methods.loadVrcxId = async function () { - this.vrcxId = await configRepository.getString('VRCX_id', ''); - if (!this.vrcxId) { - this.vrcxId = crypto.randomUUID(); - await configRepository.setString('VRCX_id', this.vrcxId); - } - }; - - $app.methods.updateIsGameRunning = async function ( - isGameRunning, - isSteamVRRunning, - isHmdAfk - ) { - if (this.gameLogDisabled) { - return; - } - if (isGameRunning !== this.isGameRunning) { - this.isGameRunning = isGameRunning; - if (isGameRunning) { - API.currentUser.$online_for = Date.now(); - API.currentUser.$offline_for = ''; - API.currentUser.$previousAvatarSwapTime = Date.now(); - } else { - await configRepository.setBool('isGameNoVR', this.isGameNoVR); - API.currentUser.$online_for = ''; - API.currentUser.$offline_for = Date.now(); - this.removeAllQueuedInstances(); - this.autoVRChatCacheManagement(); - this.checkIfGameCrashed(); - this.ipcTimeout = 0; - this.addAvatarWearTime(API.currentUser.currentAvatar); - API.currentUser.$previousAvatarSwapTime = ''; - } - this.lastLocationReset(); - this.clearNowPlaying(); - this.updateVRLastLocation(); - workerTimers.setTimeout( - () => this.checkVRChatDebugLogging(), - 60000 - ); - this.nextDiscordUpdate = 0; - console.log(new Date(), 'isGameRunning', isGameRunning); - } - - if (isSteamVRRunning !== this.isSteamVRRunning) { - this.isSteamVRRunning = isSteamVRRunning; - console.log('isSteamVRRunning:', isSteamVRRunning); - } - if (isHmdAfk !== this.isHmdAfk) { - this.isHmdAfk = isHmdAfk; - console.log('isHmdAfk:', isHmdAfk); - } - this.updateOpenVR(); - }; - - $app.data.debug = false; - $app.data.debugWebRequests = false; - $app.data.debugWebSocket = false; - $app.data.debugUserDiff = false; - $app.data.debugCurrentUserDiff = false; - $app.data.debugPhotonLogging = false; - $app.data.debugGameLog = false; - $app.data.debugFriendState = false; - - $app.data.menuActiveIndex = 'feed'; - - $app.methods.notifyMenu = function (index) { - const navRef = this.$refs.menu.$children[0]; - if (this.menuActiveIndex !== index) { - const item = navRef.items[index]; - if (item) { - item.$el.classList.add('notify'); - } - } - }; - - $app.methods.selectMenu = function (index) { - this.menuActiveIndex = index; - const item = this.$refs.menu.$children[0]?.items[index]; - if (item) { - item.$el.classList.remove('notify'); - } - if (index === 'notification') { - this.unseenNotifications = []; - } - }; - - $app.data.twoFactorAuthDialogVisible = false; - - API.$on('LOGIN', function () { - $app.twoFactorAuthDialogVisible = false; - }); - - $app.methods.clearCookiesTryLogin = async function () { - await webApiService.clearCookies(); - if (this.loginForm.lastUserLoggedIn) { - var user = - this.loginForm.savedCredentials[ - this.loginForm.lastUserLoggedIn - ]; - if (typeof user !== 'undefined') { - delete user.cookies; - await this.relogin(user); - return; - } - } - }; - - $app.methods.resendEmail2fa = async function () { - if (this.loginForm.lastUserLoggedIn) { - var user = - this.loginForm.savedCredentials[ - this.loginForm.lastUserLoggedIn - ]; - if (typeof user !== 'undefined') { - await webApiService.clearCookies(); - delete user.cookies; - this.relogin(user).then(() => { - new Noty({ - type: 'success', - text: 'Email 2FA resent.' - }).show(); - }); - return; - } - } - new Noty({ - type: 'error', - text: 'Cannot send 2FA email without saved credentials. Please login again.' - }).show(); - }; - - API.$on('USER:2FA', function () { - AppApi.FocusWindow(); - $app.promptTOTP(); - }); - - API.$on('USER:EMAILOTP', function () { - AppApi.FocusWindow(); - $app.promptEmailOTP(); - }); - - API.$on('LOGOUT', function () { - if (this.isLoggedIn) { - new Noty({ - type: 'success', - text: `See you again, ${$app.escapeTag( - this.currentUser.displayName - )}!` - }).show(); - } - this.isLoggedIn = false; - $app.friendLogInitStatus = false; - $app.notificationInitStatus = false; - }); - - API.$on('LOGIN', function (args) { - new Noty({ - type: 'success', - text: `Hello there, ${$app.escapeTag( - args.ref.displayName - )}!` - }).show(); - $app.updateStoredUser(this.currentUser); - }); - - API.$on('LOGOUT', async function () { - await $app.updateStoredUser(this.currentUser); - webApiService.clearCookies(); - // eslint-disable-next-line require-atomic-updates - $app.loginForm.lastUserLoggedIn = ''; - await configRepository.remove('lastUserLoggedIn'); - // workerTimers.setTimeout(() => location.reload(), 500); - }); - - $app.methods.checkPrimaryPassword = function (args) { - return new Promise((resolve, reject) => { - if (!this.enablePrimaryPassword) { - resolve(args.password); - } - $app.$prompt( - $t('prompt.primary_password.description'), - $t('prompt.primary_password.header'), - { - inputType: 'password', - inputPattern: /[\s\S]{1,32}/ - } - ) - .then(({ value }) => { - security - .decrypt(args.password, value) - .then(resolve) - .catch(reject); - }) - .catch(reject); - }); - }; - - $app.data.enablePrimaryPassword = await configRepository.getBool( - 'enablePrimaryPassword', - false - ); - $app.data.enablePrimaryPasswordDialog = { - visible: false, - password: '', - rePassword: '', - beforeClose(done) { - $app._data.enablePrimaryPassword = false; - done(); - } - }; - $app.methods.enablePrimaryPasswordChange = function () { - // The function is only called in adv settings - this.enablePrimaryPassword = !this.enablePrimaryPassword; - - this.enablePrimaryPasswordDialog.password = ''; - this.enablePrimaryPasswordDialog.rePassword = ''; - if (this.enablePrimaryPassword) { - this.enablePrimaryPasswordDialog.visible = true; - } else { - this.$prompt( - $t('prompt.primary_password.description'), - $t('prompt.primary_password.header'), - { - inputType: 'password', - inputPattern: /[\s\S]{1,32}/ - } - ) - .then(({ value }) => { - for (let userId in this.loginForm.savedCredentials) { - security - .decrypt( - this.loginForm.savedCredentials[userId] - .loginParmas.password, - value - ) - .then(async (pt) => { - this.saveCredentials = { - username: - this.loginForm.savedCredentials[userId] - .loginParmas.username, - password: pt - }; - await this.updateStoredUser( - this.loginForm.savedCredentials[userId].user - ); - await configRepository.setBool( - 'enablePrimaryPassword', - false - ); - }) - .catch(async () => { - this.enablePrimaryPassword = true; - await configRepository.setBool( - 'enablePrimaryPassword', - true - ); - }); - } - }) - .catch(async () => { - this.enablePrimaryPassword = true; - await configRepository.setBool( - 'enablePrimaryPassword', - true - ); - }); - } - }; - $app.methods.setPrimaryPassword = async function () { - await configRepository.setBool( - 'enablePrimaryPassword', - this.enablePrimaryPassword - ); - this.enablePrimaryPasswordDialog.visible = false; - if (this.enablePrimaryPassword) { - let key = this.enablePrimaryPasswordDialog.password; - for (let userId in this.loginForm.savedCredentials) { - security - .encrypt( - this.loginForm.savedCredentials[userId].loginParmas - .password, - key - ) - .then((ct) => { - this.saveCredentials = { - username: - this.loginForm.savedCredentials[userId] - .loginParmas.username, - password: ct - }; - this.updateStoredUser( - this.loginForm.savedCredentials[userId].user - ); - }); - } - } - }; - - $app.methods.updateStoredUser = async function (user) { - var savedCredentials = {}; - if ((await configRepository.getString('savedCredentials')) !== null) { - savedCredentials = JSON.parse( - await configRepository.getString('savedCredentials') - ); - } - if (this.saveCredentials) { - var credentialsToSave = { - user, - loginParmas: this.saveCredentials - }; - savedCredentials[user.id] = credentialsToSave; - delete this.saveCredentials; - } else if (typeof savedCredentials[user.id] !== 'undefined') { - savedCredentials[user.id].user = user; - savedCredentials[user.id].cookies = - await webApiService.getCookies(); - } - this.loginForm.savedCredentials = savedCredentials; - var jsonCredentialsArray = JSON.stringify(savedCredentials); - await configRepository.setString( - 'savedCredentials', - jsonCredentialsArray - ); - this.loginForm.lastUserLoggedIn = user.id; - await configRepository.setString('lastUserLoggedIn', user.id); - }; - - $app.methods.migrateStoredUsers = async function () { - var savedCredentials = {}; - if ((await configRepository.getString('savedCredentials')) !== null) { - savedCredentials = JSON.parse( - await configRepository.getString('savedCredentials') - ); - } - for (let name in savedCredentials) { - var userId = savedCredentials[name]?.user?.id; - if (userId && userId !== name) { - savedCredentials[userId] = savedCredentials[name]; - delete savedCredentials[name]; - } - } - await configRepository.setString( - 'savedCredentials', - JSON.stringify(savedCredentials) - ); - }; - - // #endregion - // #region | App: Friends - - $app.data.friends = new Map(); - $app.data.pendingActiveFriends = new Set(); - $app.data.friendNumber = 0; - $app.data.isFriendsGroupMe = true; - $app.data.isVIPFriends = true; - $app.data.isOnlineFriends = true; - $app.data.isActiveFriends = true; - $app.data.isOfflineFriends = false; - $app.data.isGroupInstances = false; - $app.data.groupInstances = []; - $app.data.vipFriends_ = []; - $app.data.onlineFriends_ = []; - $app.data.activeFriends_ = []; - $app.data.offlineFriends_ = []; - $app.data.sortVIPFriends = false; - $app.data.sortOnlineFriends = false; - $app.data.sortActiveFriends = false; - $app.data.sortOfflineFriends = false; - - $app.methods.fetchActiveFriend = function (userId) { - this.pendingActiveFriends.add(userId); - // FIXME: handle error - return userRequest - .getUser({ - userId - }) - .then((args) => { - this.pendingActiveFriends.delete(userId); - return args; - }); - }; - - API.$on('USER:CURRENT', function (args) { - $app.checkActiveFriends(args.json); - }); - - $app.methods.checkActiveFriends = function (ref) { - if ( - Array.isArray(ref.activeFriends) === false || - !this.friendLogInitStatus - ) { - return; - } - for (var userId of ref.activeFriends) { - if (this.pendingActiveFriends.has(userId)) { - continue; - } - var user = API.cachedUsers.get(userId); - if (typeof user !== 'undefined' && user.status !== 'offline') { - continue; - } - if (this.pendingActiveFriends.size >= 5) { - break; - } - this.fetchActiveFriend(userId); - } - }; - - API.$on('LOGIN', function () { - $app.friends.clear(); - $app.pendingActiveFriends.clear(); - $app.friendNumber = 0; - $app.isGroupInstances = false; - $app.groupInstances = []; - $app.vipFriends_ = []; - $app.onlineFriends_ = []; - $app.activeFriends_ = []; - $app.offlineFriends_ = []; - $app.sortVIPFriends = false; - $app.sortOnlineFriends = false; - $app.sortActiveFriends = false; - $app.sortOfflineFriends = false; - $app.updateInGameGroupOrder(); - }); - - API.$on('USER:CURRENT', function (args) { - // USER:CURRENT에서 처리를 함 - if ($app.friendLogInitStatus) { - $app.refreshFriends(args.ref, args.fromGetCurrentUser); - } - $app.updateOnlineFriendCoutner(); - - if ($app.randomUserColours) { - $app.getNameColour(this.currentUser.id).then((colour) => { - this.currentUser.$userColour = colour; - }); - } - }); - - API.$on('FRIEND:ADD', function (args) { - $app.addFriend(args.params.userId); - }); - - API.$on('FRIEND:DELETE', function (args) { - $app.deleteFriend(args.params.userId); - }); - - API.$on('FRIEND:STATE', function (args) { - $app.updateFriend({ - id: args.params.userId, - state: args.json.state - }); - }); - - API.$on('FAVORITE', function (args) { - $app.updateFriend({ id: args.ref.favoriteId }); - }); - - API.$on('FAVORITE:@DELETE', function (args) { - $app.updateFriend({ id: args.ref.favoriteId }); - }); - - $app.methods.refreshFriendsList = async function () { - // If we just got user less then 2 min before code call, don't call it again - if (this.nextCurrentUserRefresh < 300) { - await API.getCurrentUser().catch((err) => { - console.error(err); - }); - } - await API.refreshFriends().catch((err) => { - console.error(err); - }); - API.reconnectWebSocket(); - }; - - $app.methods.refreshFriends = function (ref, fromGetCurrentUser) { - var map = new Map(); - for (var id of ref.friends) { - map.set(id, 'offline'); - } - for (var id of ref.offlineFriends) { - map.set(id, 'offline'); - } - for (var id of ref.activeFriends) { - map.set(id, 'active'); - } - for (var id of ref.onlineFriends) { - map.set(id, 'online'); - } - for (var [id, state] of map) { - if (this.friends.has(id)) { - this.updateFriend({ id, state, fromGetCurrentUser }); - } else { - this.addFriend(id, state); - } - } - for (var id of this.friends.keys()) { - if (map.has(id) === false) { - this.deleteFriend(id); - } - } - }; - - $app.methods.addFriend = function (id, state) { - if (this.friends.has(id)) { - return; - } - var ref = API.cachedUsers.get(id); - var isVIP = this.localFavoriteFriends.has(id); - var name = ''; - var friend = this.friendLog.get(id); - if (friend) { - name = friend.displayName; - } - var ctx = { - id, - state: state || 'offline', - isVIP, - ref, - name, - memo: '', - pendingOffline: false, - pendingOfflineTime: '', - pendingState: '', - $nickName: '' - }; - if (this.friendLogInitStatus) { - this.getUserMemo(id).then((memo) => { - if (memo.userId === id) { - ctx.memo = memo.memo; - ctx.$nickName = ''; - if (memo.memo) { - var array = memo.memo.split('\n'); - ctx.$nickName = array[0]; - } - } - }); - } - if (typeof ref === 'undefined') { - var friendLogRef = this.friendLog.get(id); - if (friendLogRef?.displayName) { - ctx.name = friendLogRef.displayName; - } - } else { - ctx.name = ref.name; - } - this.friends.set(id, ctx); - if (ctx.state === 'online') { - if (ctx.isVIP) { - this.vipFriends_.push(ctx); - this.sortVIPFriends = true; - } else { - this.onlineFriends_.push(ctx); - this.sortOnlineFriends = true; - } - } else if (ctx.state === 'active') { - this.activeFriends_.push(ctx); - this.sortActiveFriends = true; - } else { - this.offlineFriends_.push(ctx); - this.sortOfflineFriends = true; - } - }; - - $app.methods.deleteFriend = function (id) { - var ctx = this.friends.get(id); - if (typeof ctx === 'undefined') { - return; - } - this.friends.delete(id); - if (ctx.state === 'online') { - if (ctx.isVIP) { - $app.removeFromArray(this.vipFriends_, ctx); - } else { - $app.removeFromArray(this.onlineFriends_, ctx); - } - } else if (ctx.state === 'active') { - $app.removeFromArray(this.activeFriends_, ctx); - } else { - $app.removeFromArray(this.offlineFriends_, ctx); - } - }; - - $app.methods.updateFriend = function (ctx) { - var { id, state, fromGetCurrentUser } = ctx; - var stateInput = state; - var ctx = this.friends.get(id); - if (typeof ctx === 'undefined') { - return; - } - var ref = API.cachedUsers.get(id); - if (stateInput) { - ctx.pendingState = stateInput; - if (typeof ref !== 'undefined') { - ctx.ref.state = stateInput; - } - } - if (stateInput === 'online') { - if (this.debugFriendState && ctx.pendingOffline) { - var time = (Date.now() - ctx.pendingOfflineTime) / 1000; - console.log(`${ctx.name} pendingOfflineCancelTime ${time}`); - } - ctx.pendingOffline = false; - ctx.pendingOfflineTime = ''; - } - var isVIP = this.localFavoriteFriends.has(id); - var location = ''; - var $location_at = ''; - if (typeof ref !== 'undefined') { - var { location, $location_at } = ref; - } - if (typeof stateInput === 'undefined' || ctx.state === stateInput) { - // this is should be: undefined -> user - if (ctx.ref !== ref) { - ctx.ref = ref; - // NOTE - // AddFriend (CurrentUser) 이후, - // 서버에서 오는 순서라고 보면 될 듯. - if (ctx.state === 'online') { - if (this.friendLogInitStatus) { - userRequest.getUser({ - userId: id - }); - } - if (ctx.isVIP) { - this.sortVIPFriends = true; - } else { - this.sortOnlineFriends = true; - } - } - } - if (ctx.isVIP !== isVIP) { - ctx.isVIP = isVIP; - if (ctx.state === 'online') { - if (ctx.isVIP) { - $app.removeFromArray(this.onlineFriends_, ctx); - this.vipFriends_.push(ctx); - this.sortVIPFriends = true; - } else { - $app.removeFromArray(this.vipFriends_, ctx); - this.onlineFriends_.push(ctx); - this.sortOnlineFriends = true; - } - } - } - if (typeof ref !== 'undefined' && ctx.name !== ref.displayName) { - ctx.name = ref.displayName; - if (ctx.state === 'online') { - if (ctx.isVIP) { - this.sortVIPFriends = true; - } else { - this.sortOnlineFriends = true; - } - } else if (ctx.state === 'active') { - this.sortActiveFriends = true; - } else { - this.sortOfflineFriends = true; - } - } - // from getCurrentUser only, fetch user if offline in an instance - if ( - fromGetCurrentUser && - ctx.state !== 'online' && - typeof ref !== 'undefined' && - isRealInstance(ref.location) - ) { - if (this.debugFriendState) { - console.log( - `Fetching offline friend in an instance from getCurrentUser ${ctx.name}` - ); - } - userRequest.getUser({ - userId: id - }); - } - } else if ( - ctx.state === 'online' && - (stateInput === 'active' || stateInput === 'offline') - ) { - ctx.ref = ref; - ctx.isVIP = isVIP; - if (typeof ref !== 'undefined') { - ctx.name = ref.displayName; - } - if (!this.friendLogInitStatus) { - this.updateFriendDelayedCheck(ctx, location, $location_at); - return; - } - // prevent status flapping - if (ctx.pendingOffline) { - if (this.debugFriendState) { - console.log(ctx.name, 'pendingOfflineAlreadyWaiting'); - } - return; - } - if (this.debugFriendState) { - console.log(ctx.name, 'pendingOfflineBegin'); - } - ctx.pendingOffline = true; - ctx.pendingOfflineTime = Date.now(); - // wait 2minutes then check if user came back online - workerTimers.setTimeout(() => { - if (!ctx.pendingOffline) { - if (this.debugFriendState) { - console.log(ctx.name, 'pendingOfflineAlreadyCancelled'); - } - return; - } - ctx.pendingOffline = false; - ctx.pendingOfflineTime = ''; - if (ctx.pendingState === ctx.state) { - if (this.debugFriendState) { - console.log( - ctx.name, - 'pendingOfflineCancelledStateMatched' - ); - } - return; - } - if (this.debugFriendState) { - console.log(ctx.name, 'pendingOfflineEnd'); - } - this.updateFriendDelayedCheck(ctx, location, $location_at); - }, this.pendingOfflineDelay); - } else { - ctx.ref = ref; - ctx.isVIP = isVIP; - if (typeof ref !== 'undefined') { - ctx.name = ref.displayName; - - // wtf, from getCurrentUser only, fetch user if online in offline location - if (fromGetCurrentUser && stateInput === 'online') { - if (this.debugFriendState) { - console.log( - `Fetching friend coming online from getCurrentUser ${ctx.name}` - ); - } - userRequest.getUser({ - userId: id - }); - return; - } - } - - this.updateFriendDelayedCheck(ctx, location, $location_at); - } - }; - - $app.methods.updateFriendDelayedCheck = async function ( - ctx, - location, - $location_at - ) { - var id = ctx.id; - var newState = ctx.pendingState; - if (this.debugFriendState) { - console.log( - `${ctx.name} updateFriendState ${ctx.state} -> ${newState}` - ); - if ( - typeof ctx.ref !== 'undefined' && - location !== ctx.ref.location - ) { - console.log( - `${ctx.name} pendingOfflineLocation ${location} -> ${ctx.ref.location}` - ); - } - } - if (!this.friends.has(id)) { - console.log('Friend not found', id); - return; - } - var isVIP = this.localFavoriteFriends.has(id); - var ref = ctx.ref; - if (ctx.state !== newState && typeof ctx.ref !== 'undefined') { - if ( - (newState === 'offline' || newState === 'active') && - ctx.state === 'online' - ) { - ctx.ref.$online_for = ''; - ctx.ref.$offline_for = Date.now(); - ctx.ref.$active_for = ''; - if (newState === 'active') { - ctx.ref.$active_for = Date.now(); - } - var ts = Date.now(); - var time = ts - $location_at; - var worldName = await this.getWorldName(location); - var groupName = await this.getGroupName(location); - var feed = { - created_at: new Date().toJSON(), - type: 'Offline', - userId: ref.id, - displayName: ref.displayName, - location, - worldName, - groupName, - time - }; - this.addFeed(feed); - database.addOnlineOfflineToDatabase(feed); - } else if ( - newState === 'online' && - (ctx.state === 'offline' || ctx.state === 'active') - ) { - ctx.ref.$previousLocation = ''; - ctx.ref.$travelingToTime = Date.now(); - ctx.ref.$location_at = Date.now(); - ctx.ref.$online_for = Date.now(); - ctx.ref.$offline_for = ''; - ctx.ref.$active_for = ''; - var worldName = await this.getWorldName(location); - var groupName = await this.getGroupName(location); - var feed = { - created_at: new Date().toJSON(), - type: 'Online', - userId: id, - displayName: ctx.name, - location, - worldName, - groupName, - time: '' - }; - this.addFeed(feed); - database.addOnlineOfflineToDatabase(feed); - } - if (newState === 'active') { - ctx.ref.$active_for = Date.now(); - } - } - if (ctx.state === 'online') { - if (ctx.isVIP) { - $app.removeFromArray(this.vipFriends_, ctx); - } else { - $app.removeFromArray(this.onlineFriends_, ctx); - } - } else if (ctx.state === 'active') { - $app.removeFromArray(this.activeFriends_, ctx); - } else { - $app.removeFromArray(this.offlineFriends_, ctx); - } - if (newState === 'online') { - if (isVIP) { - this.vipFriends_.push(ctx); - this.sortVIPFriends = true; - } else { - this.onlineFriends_.push(ctx); - this.sortOnlineFriends = true; - } - } else if (newState === 'active') { - this.activeFriends_.push(ctx); - this.sortActiveFriends = true; - } else { - this.offlineFriends_.push(ctx); - this.sortOfflineFriends = true; - } - if (ctx.state !== newState) { - this.updateOnlineFriendCoutner(); - } - ctx.state = newState; - if (ref?.displayName) { - ctx.name = ref.displayName; - } - ctx.isVIP = isVIP; - }; - - $app.methods.getWorldName = async function (location) { - var worldName = ''; - try { - var L = parseLocation(location); - if (L.isRealInstance && L.worldId) { - var args = await worldRequest.getCachedWorld({ - worldId: L.worldId - }); - worldName = args.ref.name; - } - } catch (e) { - throw e; - } - return worldName; - }; - - $app.methods.getGroupName = async function (data) { - if (!data) { - return ''; - } - var groupName = ''; - var groupId = data; - if (!data.startsWith('grp_')) { - var L = parseLocation(data); - groupId = L.groupId; - if (!L.groupId) { - return ''; - } - } - try { - var args = await API.getCachedGroup({ - groupId - }); - groupName = args.ref.name; - } catch (err) {} - return groupName; - }; - - $app.methods.updateFriendGPS = function (userId) { - var ctx = this.friends.get(userId); - if (ctx.isVIP) { - this.sortVIPFriends = true; - } else { - this.sortOnlineFriends = true; - } - }; - - $app.data.onlineFriendCount = 0; - $app.methods.updateOnlineFriendCoutner = function () { - var onlineFriendCount = - this.vipFriends.length + this.onlineFriends.length; - if (onlineFriendCount !== this.onlineFriendCount) { - AppApi.ExecuteVrFeedFunction( - 'updateOnlineFriendCount', - `${onlineFriendCount}` - ); - this.onlineFriendCount = onlineFriendCount; - } - }; - - // ascending - var compareByDisplayName = function (a, b) { - if ( - typeof a.displayName !== 'string' || - typeof b.displayName !== 'string' - ) { - return 0; - } - return a.displayName.localeCompare(b.displayName); - }; - - var compareByMemberCount = function (a, b) { - if ( - typeof a.memberCount !== 'number' || - typeof b.memberCount !== 'number' - ) { - return 0; - } - return a.memberCount - b.memberCount; - }; - - // private - var compareByPrivate = function (a, b) { - if (typeof a.ref === 'undefined' || typeof b.ref === 'undefined') { - return 0; - } - if (a.ref.location === 'private' && b.ref.location === 'private') { - return 0; - } else if (a.ref.location === 'private') { - return 1; - } else if (b.ref.location === 'private') { - return -1; - } - return 0; - }; - - var compareByStatus = function (a, b) { - if (typeof a.ref === 'undefined' || typeof b.ref === 'undefined') { - return 0; - } - if (a.ref.status === b.ref.status) { - return 0; - } - if (a.ref.state === 'offline') { - return 1; - } - return $app.sortStatus(a.ref.status, b.ref.status); - }; - - $app.methods.sortStatus = function (a, b) { - switch (b) { - case 'join me': - switch (a) { - case 'active': - return 1; - case 'ask me': - return 1; - case 'busy': - return 1; - } - break; - case 'active': - switch (a) { - case 'join me': - return -1; - case 'ask me': - return 1; - case 'busy': - return 1; - } - break; - case 'ask me': - switch (a) { - case 'join me': - return -1; - case 'active': - return -1; - case 'busy': - return 1; - } - break; - case 'busy': - switch (a) { - case 'join me': - return -1; - case 'active': - return -1; - case 'ask me': - return -1; - } - break; - } - return 0; - }; - - // location at - var compareByLocationAt = function (a, b) { - if (a.location === 'traveling' && b.location === 'traveling') { - return 0; - } - if (a.location === 'traveling') { - return 1; - } - if (b.location === 'traveling') { - return -1; - } - if (a.$location_at < b.$location_at) { - return -1; - } - if (a.$location_at > b.$location_at) { - return 1; - } - return 0; - }; - - // location at but for the sidebar - var compareByLocation = function (a, b) { - if (typeof a.ref === 'undefined' || typeof b.ref === 'undefined') { - return 0; - } - if (a.state !== 'online' || b.state !== 'online') { - return 0; - } - - return a.ref.location.localeCompare(b.ref.location); - }; - - var compareByActivityField = function (a, b, field) { - if (typeof a.ref === 'undefined' || typeof b.ref === 'undefined') { - return 0; - } - - // When the field is just and empty string, it means they've been - // in whatever active state for the longest - if ( - a.ref[field] < b.ref[field] || - (a.ref[field] !== '' && b.ref[field] === '') - ) { - return 1; - } - if ( - a.ref[field] > b.ref[field] || - (a.ref[field] === '' && b.ref[field] !== '') - ) { - return -1; - } - return 0; - }; - - // last active - var compareByLastActive = function (a, b) { - if (a.state === 'online' && b.state === 'online') { - if ( - a.ref?.$online_for && - b.ref?.$online_for && - a.ref.$online_for === b.ref.$online_for - ) { - compareByActivityField(a, b, 'last_login'); - } - return compareByActivityField(a, b, '$online_for'); - } - - return compareByActivityField(a, b, 'last_activity'); - }; - - // last seen - var compareByLastSeen = function (a, b) { - return compareByActivityField(a, b, '$lastSeen'); - }; - - var getFriendsSortFunction = function (sortMethods) { - const sorts = []; - for (const sortMethod of sortMethods) { - switch (sortMethod) { - case 'Sort Alphabetically': - sorts.push($utils.compareByName); - break; - case 'Sort Private to Bottom': - sorts.push(compareByPrivate); - break; - case 'Sort by Status': - sorts.push(compareByStatus); - break; - case 'Sort by Last Active': - sorts.push(compareByLastActive); - break; - case 'Sort by Last Seen': - sorts.push(compareByLastSeen); - break; - case 'Sort by Time in Instance': - sorts.push((a, b) => { - if ( - typeof a.ref === 'undefined' || - typeof b.ref === 'undefined' - ) { - return 0; - } - if (a.state !== 'online' || b.state !== 'online') { - return 0; - } - - return compareByLocationAt(b.ref, a.ref); - }); - break; - case 'Sort by Location': - sorts.push(compareByLocation); - break; - case 'None': - sorts.push(() => 0); - break; - } - } - - return (a, b) => { - let res; - for (const sort of sorts) { - res = sort(a, b); - if (res !== 0) { - return res; - } - } - return res; - }; - }; - - // VIP friends - $app.computed.vipFriends = function () { - if (!this.sortVIPFriends) { - return this.vipFriends_; - } - this.sortVIPFriends = false; - - this.vipFriends_.sort(getFriendsSortFunction(this.sidebarSortMethods)); - return this.vipFriends_; - }; - - // Online friends - $app.computed.onlineFriends = function () { - if (!this.sortOnlineFriends) { - return this.onlineFriends_; - } - this.sortOnlineFriends = false; - - this.onlineFriends_.sort( - getFriendsSortFunction(this.sidebarSortMethods) - ); - - return this.onlineFriends_; - }; - - // Active friends - $app.computed.activeFriends = function () { - if (!this.sortActiveFriends) { - return this.activeFriends_; - } - this.sortActiveFriends = false; - - this.activeFriends_.sort( - getFriendsSortFunction(this.sidebarSortMethods) - ); - - return this.activeFriends_; - }; - - // Offline friends - $app.computed.offlineFriends = function () { - if (!this.sortOfflineFriends) { - return this.offlineFriends_; - } - this.sortOfflineFriends = false; - - this.offlineFriends_.sort( - getFriendsSortFunction(this.sidebarSortMethods) - ); - - return this.offlineFriends_; - }; - - $app.methods.userStatusClass = function (user, pendingOffline) { - var style = {}; - if (typeof user === 'undefined') { - return style; - } - var id = ''; - if (user.id) { - id = user.id; - } else if (user.userId) { - id = user.userId; - } - if (id === API.currentUser.id) { - return this.statusClass(user.status); - } - if (!user.isFriend) { - return style; - } - if (pendingOffline) { - // Pending offline - style.offline = true; - } else if ( - user.status !== 'active' && - user.location === 'private' && - user.state === '' && - id && - !API.currentUser.onlineFriends.includes(id) - ) { - // temp fix - if (API.currentUser.activeFriends.includes(id)) { - // Active - style.active = true; - } else { - // Offline - style.offline = true; - } - } else if (user.state === 'active') { - // Active - style.active = true; - } else if (user.location === 'offline') { - // Offline - style.offline = true; - } else if (user.status === 'active') { - // Online - style.online = true; - } else if (user.status === 'join me') { - // Join Me - style.joinme = true; - } else if (user.status === 'ask me') { - // Ask Me - style.askme = true; - } else if (user.status === 'busy') { - // Do Not Disturb - style.busy = true; - } - if ( - user.platform && - user.platform !== 'standalonewindows' && - user.platform !== 'web' - ) { - style.mobile = true; - } - if ( - user.last_platform && - user.last_platform !== 'standalonewindows' && - user.platform === 'web' - ) { - style.mobile = true; - } - return style; - }; - - $app.methods.statusClass = function (status) { - var style = {}; - if (typeof status !== 'undefined') { - if (status === 'active') { - // Online - style.online = true; - } else if (status === 'join me') { - // Join Me - style.joinme = true; - } else if (status === 'ask me') { - // Ask Me - style.askme = true; - } else if (status === 'busy') { - // Do Not Disturb - style.busy = true; - } - } - return style; - }; - - $app.methods.confirmDeleteFriend = function (id) { - this.$confirm('Continue? Unfriend', 'Confirm', { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - callback: (action) => { - if (action === 'confirm') { - friendRequest.deleteFriend({ - userId: id - }); - } - } - }); - }; - - // #endregion - // #region | App: Quick Search - - $app.data.quickSearchItems = []; - - // Making a persistent comparer increases perf by like 10x lmao - $app.data._stringComparer = undefined; - $app.computed.stringComparer = function () { - if (typeof this._stringComparer === 'undefined') { - this._stringComparer = Intl.Collator( - this.appLanguage.replace('_', '-'), - { usage: 'search', sensitivity: 'base' } - ); - } - return this._stringComparer; - }; - - $app.methods.quickSearchRemoteMethod = function (query) { - if (!query) { - this.quickSearchItems = this.quickSearchUserHistory(); - return; - } - - const results = []; - const cleanQuery = removeWhitespace(query); - - for (let ctx of this.friends.values()) { - if (typeof ctx.ref === 'undefined') { - continue; - } - - const cleanName = removeConfusables(ctx.name); - let match = $utils.localeIncludes( - cleanName, - cleanQuery, - this.stringComparer - ); - if (!match) { - // Also check regular name in case search is with special characters - match = $utils.localeIncludes( - ctx.name, - cleanQuery, - this.stringComparer - ); - } - // Use query with whitespace for notes and memos as people are more - // likely to include spaces in memos and notes - if (!match && ctx.memo) { - match = $utils.localeIncludes( - ctx.memo, - query, - this.stringComparer - ); - } - if (!match && ctx.ref.note) { - match = $utils.localeIncludes( - ctx.ref.note, - query, - this.stringComparer - ); - } - - if (match) { - results.push({ - value: ctx.id, - label: ctx.name, - ref: ctx.ref, - name: ctx.name - }); - } - } - - results.sort(function (a, b) { - var A = - $app.stringComparer.compare( - a.name.substring(0, cleanQuery.length), - cleanQuery - ) === 0; - var B = - $app.stringComparer.compare( - b.name.substring(0, cleanQuery.length), - cleanQuery - ) === 0; - if (A && !B) { - return -1; - } else if (B && !A) { - return 1; - } - return $utils.compareByName(a, b); - }); - if (results.length > 4) { - results.length = 4; - } - results.push({ - value: `search:${query}`, - label: query - }); - - this.quickSearchItems = results; - }; - - $app.methods.quickSearchChange = function (value) { - if (value) { - if (value.startsWith('search:')) { - const searchText = value.substr(7); - if (this.quickSearchItems.length > 1 && searchText.length) { - this.friendsListSearch = searchText; - this.menuActiveIndex = 'friendList'; - } else { - this.menuActiveIndex = 'search'; - this.searchText = searchText; - this.lookupUser({ displayName: searchText }); - } - } else { - this.showUserDialog(value); - } - } - }; - - // #endregion - // #region | App: Quick Search User History - - $app.data.showUserDialogHistory = new Set(); - - $app.methods.quickSearchUserHistory = function () { - var userHistory = Array.from(this.showUserDialogHistory.values()) - .reverse() - .slice(0, 5); - var results = []; - userHistory.forEach((userId) => { - var ref = API.cachedUsers.get(userId); - if (typeof ref !== 'undefined') { - results.push({ - value: ref.id, - label: ref.name, - ref - }); - } - }); - return results; - }; - - // #endregion - // #region | App: Feed - - $app.data.tablePageSize = await configRepository.getInt( - 'VRCX_tablePageSize', - 15 - ); - - $app.data.gameLogTable.pageSize = $app.data.tablePageSize; - $app.data.feedTable.pageSize = $app.data.tablePageSize; - - $app.data.dontLogMeOut = false; - - API.$on('LOGIN', async function (args) { - // early loading indicator - this.isRefreshFriendsLoading = true; - $app.feedTable.loading = true; - - $app.friendLog = new Map(); - $app.feedTable.data = []; - $app.feedSessionTable = []; - $app.friendLogInitStatus = false; - $app.notificationInitStatus = false; - await database.initUserTables(args.json.id); - $app.menuActiveIndex = 'feed'; - await $app.updateDatabaseVersion(); - // eslint-disable-next-line require-atomic-updates - $app.gameLogTable.data = await database.lookupGameLogDatabase( - $app.gameLogTable.search, - $app.gameLogTable.filter - ); - // eslint-disable-next-line require-atomic-updates - $app.feedSessionTable = await database.getFeedDatabase(); - await $app.feedTableLookup(); - // eslint-disable-next-line require-atomic-updates - $app.notificationTable.data = await database.getNotifications(); - this.refreshNotifications(); - $app.loadCurrentUserGroups(args.json.id, args.json?.presence?.groups); - try { - if ( - await configRepository.getBool(`friendLogInit_${args.json.id}`) - ) { - await $app.getFriendLog(args.ref); - } else { - await $app.initFriendLog(args.ref); - } - } catch (err) { - if (!$app.dontLogMeOut) { - $app.$message({ - message: $t('message.friend.load_failed'), - type: 'error' - }); - this.logout(); - throw err; - } - } - await $app.getAvatarHistory(); - await $app.getAllUserMemos(); - userNotes.init(); - if ($app.randomUserColours) { - $app.getNameColour(this.currentUser.id).then((colour) => { - this.currentUser.$userColour = colour; - }); - await $app.userColourInit(); - } - await $app.getAllUserStats(); - $app.sortVIPFriends = true; - $app.sortOnlineFriends = true; - $app.sortActiveFriends = true; - $app.sortOfflineFriends = true; - this.getAuth(); - $app.updateSharedFeed(true); - if ($app.isGameRunning) { - $app.loadPlayerList(); - } - $app.vrInit(); - // remove old data from json file and migrate to SQLite - if (await VRCXStorage.Get(`${args.json.id}_friendLogUpdatedAt`)) { - VRCXStorage.Remove(`${args.json.id}_feedTable`); - $app.migrateMemos(); - $app.migrateFriendLog(args.json.id); - } - await AppApi.IPCAnnounceStart(); - }); - - $app.methods.loadPlayerList = function () { - var data = this.gameLogSessionTable; - if (data.length === 0) { - return; - } - var length = 0; - for (var i = data.length - 1; i > -1; i--) { - var ctx = data[i]; - if (ctx.type === 'Location') { - this.lastLocation = { - date: Date.parse(ctx.created_at), - location: ctx.location, - name: ctx.worldName, - playerList: new Map(), - friendList: new Map() - }; - length = i; - break; - } - } - if (length > 0) { - for (var i = length + 1; i < data.length; i++) { - var ctx = data[i]; - if (ctx.type === 'OnPlayerJoined') { - if (!ctx.userId) { - for (var ref of API.cachedUsers.values()) { - if (ref.displayName === ctx.displayName) { - ctx.userId = ref.id; - break; - } - } - } - var userMap = { - displayName: ctx.displayName, - userId: ctx.userId, - joinTime: Date.parse(ctx.created_at), - lastAvatar: '' - }; - this.lastLocation.playerList.set(ctx.userId, userMap); - if (this.friends.has(ctx.userId)) { - this.lastLocation.friendList.set(ctx.userId, userMap); - } - } - if (ctx.type === 'OnPlayerLeft') { - this.lastLocation.playerList.delete(ctx.userId); - this.lastLocation.friendList.delete(ctx.userId); - } - } - this.lastLocation.playerList.forEach((ref1) => { - if ( - ref1.userId && - typeof ref1.userId === 'string' && - !API.cachedUsers.has(ref1.userId) - ) { - userRequest.getUser({ userId: ref1.userId }); - } - }); - - this.updateCurrentUserLocation(); - this.updateCurrentInstanceWorld(); - this.updateVRLastLocation(); - this.getCurrentInstanceUserList(); - this.applyUserDialogLocation(); - this.applyWorldDialogInstances(); - this.applyGroupDialogInstances(); - } - }; - - $app.data.instancePlayerCount = new Map(); - $app.data.robotUrl = `${API.endpointDomain}/file/file_0e8c4e32-7444-44ea-ade4-313c010d4bae/1/file`; - - API.$on('USER:UPDATE', async function (args) { - var { ref, props } = args; - var friend = $app.friends.get(ref.id); - if (typeof friend === 'undefined') { - return; - } - if (props.location) { - // update instancePlayerCount - var previousLocation = props.location[1]; - var newLocation = props.location[0]; - var oldCount = $app.instancePlayerCount.get(previousLocation); - if (typeof oldCount !== 'undefined') { - oldCount--; - if (oldCount <= 0) { - $app.instancePlayerCount.delete(previousLocation); - } else { - $app.instancePlayerCount.set(previousLocation, oldCount); - } - } - var newCount = $app.instancePlayerCount.get(newLocation); - if (typeof newCount === 'undefined') { - newCount = 0; - } - newCount++; - $app.instancePlayerCount.set(newLocation, newCount); - } - if (props.location && ref.id === $app.userDialog.id) { - // update user dialog instance occupants - $app.applyUserDialogLocation(true); - } - if (props.location && ref.$location.worldId === $app.worldDialog.id) { - $app.applyWorldDialogInstances(); - } - if (props.location && ref.$location.groupId === $app.groupDialog.id) { - $app.applyGroupDialogInstances(); - } - if ( - !props.state && - props.location && - props.location[0] !== 'offline' && - props.location[0] !== '' && - props.location[1] !== 'offline' && - props.location[1] !== '' && - props.location[0] !== 'traveling' - ) { - // skip GPS if user is offline or traveling - var previousLocation = props.location[1]; - var newLocation = props.location[0]; - var time = props.location[2]; - if (previousLocation === 'traveling' && ref.$previousLocation) { - previousLocation = ref.$previousLocation; - var travelTime = Date.now() - ref.$travelingToTime; - time -= travelTime; - if (time < 0) { - time = 0; - } - } - if ($app.debugFriendState && previousLocation) { - console.log( - `${ref.displayName} GPS ${previousLocation} -> ${newLocation}` - ); - } - if (previousLocation === 'offline') { - previousLocation = ''; - } - if (!previousLocation) { - // no previous location - if ($app.debugFriendState) { - console.log( - ref.displayName, - 'Ignoring GPS, no previous location', - newLocation - ); - } - } else if (ref.$previousLocation === newLocation) { - // location traveled to is the same - ref.$location_at = Date.now() - time; - } else { - var worldName = await $app.getWorldName(newLocation); - var groupName = await $app.getGroupName(newLocation); - var feed = { - created_at: new Date().toJSON(), - type: 'GPS', - userId: ref.id, - displayName: ref.displayName, - location: newLocation, - worldName, - groupName, - previousLocation, - time - }; - $app.addFeed(feed); - database.addGPSToDatabase(feed); - $app.updateFriendGPS(ref.id); - // clear previousLocation after GPS - ref.$previousLocation = ''; - ref.$travelingToTime = Date.now(); - } - } - if ( - props.location && - props.location[0] === 'traveling' && - props.location[1] !== 'traveling' - ) { - // store previous location when user is traveling - ref.$previousLocation = props.location[1]; - ref.$travelingToTime = Date.now(); - $app.updateFriendGPS(ref.id); - } - var imageMatches = false; - if ( - props.currentAvatarThumbnailImageUrl && - props.currentAvatarThumbnailImageUrl[0] && - props.currentAvatarThumbnailImageUrl[1] && - props.currentAvatarThumbnailImageUrl[0] === - props.currentAvatarThumbnailImageUrl[1] - ) { - imageMatches = true; - } - if ( - (((props.currentAvatarImageUrl || - props.currentAvatarThumbnailImageUrl) && - !ref.profilePicOverride) || - props.currentAvatarTags) && - !imageMatches - ) { - var currentAvatarImageUrl = ''; - var previousCurrentAvatarImageUrl = ''; - var currentAvatarThumbnailImageUrl = ''; - var previousCurrentAvatarThumbnailImageUrl = ''; - var currentAvatarTags = ''; - var previousCurrentAvatarTags = ''; - if (props.currentAvatarImageUrl) { - currentAvatarImageUrl = props.currentAvatarImageUrl[0]; - previousCurrentAvatarImageUrl = props.currentAvatarImageUrl[1]; - } else { - currentAvatarImageUrl = ref.currentAvatarImageUrl; - previousCurrentAvatarImageUrl = ref.currentAvatarImageUrl; - } - if (props.currentAvatarThumbnailImageUrl) { - currentAvatarThumbnailImageUrl = - props.currentAvatarThumbnailImageUrl[0]; - previousCurrentAvatarThumbnailImageUrl = - props.currentAvatarThumbnailImageUrl[1]; - } else { - currentAvatarThumbnailImageUrl = - ref.currentAvatarThumbnailImageUrl; - previousCurrentAvatarThumbnailImageUrl = - ref.currentAvatarThumbnailImageUrl; - } - if (props.currentAvatarTags) { - currentAvatarTags = props.currentAvatarTags[0]; - previousCurrentAvatarTags = props.currentAvatarTags[1]; - if ( - ref.profilePicOverride && - !props.currentAvatarThumbnailImageUrl - ) { - // forget last seen avatar - ref.currentAvatarImageUrl = ''; - ref.currentAvatarThumbnailImageUrl = ''; - } - } else { - currentAvatarTags = ref.currentAvatarTags; - previousCurrentAvatarTags = ref.currentAvatarTags; - } - if (this.logEmptyAvatars || ref.currentAvatarImageUrl) { - var avatarInfo = { - ownerId: '', - avatarName: '' - }; - try { - avatarInfo = await $app.getAvatarName( - currentAvatarImageUrl - ); - } catch (err) {} - var previousAvatarInfo = { - ownerId: '', - avatarName: '' - }; - try { - previousAvatarInfo = await $app.getAvatarName( - previousCurrentAvatarImageUrl - ); - } catch (err) {} - var feed = { - created_at: new Date().toJSON(), - type: 'Avatar', - userId: ref.id, - displayName: ref.displayName, - ownerId: avatarInfo.ownerId, - previousOwnerId: previousAvatarInfo.ownerId, - avatarName: avatarInfo.avatarName, - previousAvatarName: previousAvatarInfo.avatarName, - currentAvatarImageUrl, - currentAvatarThumbnailImageUrl, - previousCurrentAvatarImageUrl, - previousCurrentAvatarThumbnailImageUrl, - currentAvatarTags, - previousCurrentAvatarTags - }; - $app.addFeed(feed); - database.addAvatarToDatabase(feed); - } - } - if (props.status || props.statusDescription) { - var status = ''; - var previousStatus = ''; - var statusDescription = ''; - var previousStatusDescription = ''; - if (props.status) { - if (props.status[0]) { - status = props.status[0]; - } - if (props.status[1]) { - previousStatus = props.status[1]; - } - } else if (ref.status) { - status = ref.status; - previousStatus = ref.status; - } - if (props.statusDescription) { - if (props.statusDescription[0]) { - statusDescription = props.statusDescription[0]; - } - if (props.statusDescription[1]) { - previousStatusDescription = props.statusDescription[1]; - } - } else if (ref.statusDescription) { - statusDescription = ref.statusDescription; - previousStatusDescription = ref.statusDescription; - } - var feed = { - created_at: new Date().toJSON(), - type: 'Status', - userId: ref.id, - displayName: ref.displayName, - status, - statusDescription, - previousStatus, - previousStatusDescription - }; - $app.addFeed(feed); - database.addStatusToDatabase(feed); - } - if (props.bio && props.bio[0] && props.bio[1]) { - var bio = ''; - var previousBio = ''; - if (props.bio[0]) { - bio = props.bio[0]; - } - if (props.bio[1]) { - previousBio = props.bio[1]; - } - var feed = { - created_at: new Date().toJSON(), - type: 'Bio', - userId: ref.id, - displayName: ref.displayName, - bio, - previousBio - }; - $app.addFeed(feed); - database.addBioToDatabase(feed); - } - }); - - /** - * Function that prepare the Longest Common Subsequence (LCS) scores matrix - * @param {*} s1 String 1 - * @param {*} s2 String 2 - * @returns - */ - $app.methods.lcsMatrix = function (s1, s2) { - const m = s1.length; - const n = s2.length; - const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); - - // Fill the matrix for LCS - for (let i = 1; i <= m; i++) { - for (let j = 1; j <= n; j++) { - if (s1[i - 1] === s2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1; - } else { - dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); - } - } - } - - return dp; - }; - - /** - * Function to find the longest common subsequence between two strings - * @param {string} str1 - * @param {string} str2 - * @returns {number[][]} A matrix that contains the longest common subsequence between both strings - */ - $app.methods.longestCommonSubsequence = function longestCommonSubsequence( - str1, - str2 - ) { - let lcs = []; - for (let i = 0; i <= str1.length; i++) { - lcs.push(new Array(str2.length + 1).fill(0)); - } - for (let i = str1.length - 1; i >= 0; i--) { - for (let j = str2.length - 1; j >= 0; j--) { - if (str1[i] == str2[j]) { - lcs[i][j] = lcs[i + 1][j + 1] + 1; - } else { - lcs[i][j] = Math.max(lcs[i + 1][j], lcs[i][j + 1]); - } - } - } - return lcs; - }; - - /** - * Merge differences in both strings to get the longest common subsequence - * @param {{text: string, type: "add" | "remove" | "same"}[]} res - * @returns {{text: string, type: "add" | "remove" | "same"}[]} An array that contains the differences between both strings - */ - $app.methods.regoupDifferences = function regoupDifferences(res) { - let regrouped = []; - let text = ''; - let type = ''; - for (let i = 0; i < res.length; i++) { - if (i == 0) { - text = res[i].text; - type = res[i].type; - } else if (res[i].type == type) { - text += res[i].text; - } else { - regrouped.push({ text: text, type: type }); - text = res[i].text; - type = res[i].type; - } - } - regrouped.push({ text: text, type: type }); - return regrouped; - }; - - // #endregion - // #region | App: gameLog - - $app.data.lastLocation = { - date: 0, - location: '', - name: '', - playerList: new Map(), - friendList: new Map() - }; - - $app.methods.lastLocationReset = function (gameLogDate) { - var dateTime = gameLogDate; - if (!gameLogDate) { - dateTime = new Date().toJSON(); - } - var dateTimeStamp = Date.parse(dateTime); - this.photonLobby = new Map(); - this.photonLobbyCurrent = new Map(); - this.photonLobbyMaster = 0; - this.photonLobbyCurrentUser = 0; - this.photonLobbyUserData = new Map(); - this.photonLobbyWatcherLoopStop(); - this.photonLobbyAvatars = new Map(); - this.photonLobbyLastModeration = new Map(); - this.photonLobbyJointime = new Map(); - this.photonLobbyActivePortals = new Map(); - this.photonEvent7List = new Map(); - this.photonLastEvent7List = ''; - this.photonLastChatBoxMsg = new Map(); - this.moderationEventQueue = new Map(); - if (this.photonEventTable.data.length > 0) { - this.photonEventTablePrevious.data = this.photonEventTable.data; - this.photonEventTable.data = []; - } - var playerList = Array.from(this.lastLocation.playerList.values()); - var dataBaseEntries = []; - for (var ref of playerList) { - var entry = { - created_at: dateTime, - type: 'OnPlayerLeft', - displayName: ref.displayName, - location: this.lastLocation.location, - userId: ref.userId, - time: dateTimeStamp - ref.joinTime - }; - dataBaseEntries.unshift(entry); - this.addGameLog(entry); - } - database.addGamelogJoinLeaveBulk(dataBaseEntries); - if (this.lastLocation.date !== 0) { - var update = { - time: dateTimeStamp - this.lastLocation.date, - created_at: new Date(this.lastLocation.date).toJSON() - }; - database.updateGamelogLocationTimeToDatabase(update); - } - this.lastLocationDestination = ''; - this.lastLocationDestinationTime = 0; - this.lastLocation = { - date: 0, - location: '', - name: '', - playerList: new Map(), - friendList: new Map() - }; - this.updateCurrentUserLocation(); - this.updateCurrentInstanceWorld(); - this.updateVRLastLocation(); - this.getCurrentInstanceUserList(); - this.lastVideoUrl = ''; - this.lastResourceloadUrl = ''; - this.applyUserDialogLocation(); - this.applyWorldDialogInstances(); - this.applyGroupDialogInstances(); - }; - - $app.data.lastLocation$ = { - tag: '', - instanceId: '', - accessType: '', - worldName: '', - worldCapacity: 0, - joinUrl: '', - statusName: '', - statusImage: '' - }; - - $app.data.lastLocationDestination = ''; - $app.data.lastLocationDestinationTime = 0; - - // It's like he's going to be used somewhere, and commenting it out would be an error or something. - $app.methods.silentSearchUser = function (displayName) { - console.log('Searching for userId for:', displayName); - var params = { - n: 5, - offset: 0, - fuzzy: false, - search: displayName - }; - userRequest.getUsers(params).then((args) => { - var map = new Map(); - var nameFound = false; - for (var json of args.json) { - var ref = API.cachedUsers.get(json.id); - if (typeof ref !== 'undefined') { - map.set(ref.id, ref); - } - if (json.displayName === displayName) { - nameFound = true; - } - } - if (!nameFound) { - console.error('userId not found for', displayName); - } - return args; - }); - }; - - $app.methods.lookupYouTubeVideo = async function (videoId) { - var data = null; - var apiKey = 'AIzaSyA-iUQCpWf5afEL3NanEOSxbzziPMU3bxY'; - if (this.youTubeApiKey) { - apiKey = this.youTubeApiKey; - } - try { - var response = await webApiService.execute({ - url: `https://www.googleapis.com/youtube/v3/videos?id=${encodeURIComponent( - videoId - )}&part=snippet,contentDetails&key=${apiKey}`, - method: 'GET', - headers: { - Referer: 'https://vrcx.app' - } - }); - var json = JSON.parse(response.data); - if (this.debugWebRequests) { - console.log(json, response); - } - if (response.status === 200) { - data = json; - } else { - throw new Error(`Error: ${response.data}`); - } - } catch { - console.error(`YouTube video lookup failed for ${videoId}`); - } - return data; - }; - - $app.data.nowPlaying = { - url: '', - name: '', - length: 0, - startTime: 0, - offset: 0, - elapsed: 0, - percentage: 0, - remainingText: '', - playing: false - }; - - $app.methods.clearNowPlaying = function () { - this.nowPlaying = { - url: '', - name: '', - length: 0, - startTime: 0, - offset: 0, - elapsed: 0, - percentage: 0, - remainingText: '', - playing: false - }; - this.updateVrNowPlaying(); - }; - - $app.methods.setNowPlaying = function (ctx) { - if (this.nowPlaying.url !== ctx.videoUrl) { - if (!ctx.userId && ctx.displayName) { - for (var ref of API.cachedUsers.values()) { - if (ref.displayName === ctx.displayName) { - ctx.userId = ref.id; - break; - } - } - } - this.queueGameLogNoty(ctx); - this.addGameLog(ctx); - database.addGamelogVideoPlayToDatabase(ctx); - - var displayName = ''; - if (ctx.displayName) { - displayName = ` (${ctx.displayName})`; - } - var name = `${ctx.videoName}${displayName}`; - this.nowPlaying = { - url: ctx.videoUrl, - name, - length: ctx.videoLength, - startTime: Date.parse(ctx.created_at) / 1000, - offset: ctx.videoPos, - elapsed: 0, - percentage: 0, - remainingText: '' - }; - } else { - this.nowPlaying = { - ...this.nowPlaying, - length: ctx.videoLength, - startTime: Date.parse(ctx.created_at) / 1000, - offset: ctx.videoPos, - elapsed: 0, - percentage: 0, - remainingText: '' - }; - } - this.updateVrNowPlaying(); - if (!this.nowPlaying.playing && ctx.videoLength > 0) { - this.nowPlaying.playing = true; - this.updateNowPlaying(); - } - }; - - $app.methods.updateNowPlaying = function () { - var np = this.nowPlaying; - if (!this.nowPlaying.playing) { - return; - } - var now = Date.now() / 1000; - np.elapsed = Math.round((now - np.startTime + np.offset) * 10) / 10; - if (np.elapsed >= np.length) { - this.clearNowPlaying(); - return; - } - np.remainingText = this.formatSeconds(np.length - np.elapsed); - np.percentage = Math.round(((np.elapsed * 100) / np.length) * 10) / 10; - this.updateVrNowPlaying(); - workerTimers.setTimeout(() => this.updateNowPlaying(), 1000); - }; - - $app.methods.updateVrNowPlaying = function () { - var json = JSON.stringify(this.nowPlaying); - AppApi.ExecuteVrFeedFunction('nowPlayingUpdate', json); - AppApi.ExecuteVrOverlayFunction('nowPlayingUpdate', json); - }; - - $app.methods.formatSeconds = function (duration) { - var pad = function (num, size) { - return `000${num}`.slice(size * -1); - }, - time = parseFloat(duration).toFixed(3), - hours = Math.floor(time / 60 / 60), - minutes = Math.floor(time / 60) % 60, - seconds = Math.floor(time - minutes * 60); - var hoursOut = ''; - if (hours > '0') { - hoursOut = `${pad(hours, 2)}:`; - } - return `${hoursOut + pad(minutes, 2)}:${pad(seconds, 2)}`; - }; - - $app.methods.convertYoutubeTime = function (duration) { - var a = duration.match(/\d+/g); - if ( - duration.indexOf('M') >= 0 && - duration.indexOf('H') === -1 && - duration.indexOf('S') === -1 - ) { - a = [0, a[0], 0]; - } - if (duration.indexOf('H') >= 0 && duration.indexOf('M') === -1) { - a = [a[0], 0, a[1]]; - } - if ( - duration.indexOf('H') >= 0 && - duration.indexOf('M') === -1 && - duration.indexOf('S') === -1 - ) { - a = [a[0], 0, 0]; - } - var length = 0; - if (a.length === 3) { - length += parseInt(a[0], 10) * 3600; - length += parseInt(a[1], 10) * 60; - length += parseInt(a[2], 10); - } - if (a.length === 2) { - length += parseInt(a[0], 10) * 60; - length += parseInt(a[1], 10); - } - if (a.length === 1) { - length += parseInt(a[0], 10); - } - return length; - }; - - $app.data.instanceTypes = [ - 'invite', - 'invite+', - 'friends', - 'friends+', - 'public', - 'groupPublic', - 'groupPlus', - 'groupOnly' - ]; - - $app.methods.updateAutoStateChange = function () { - if ( - !this.autoStateChangeEnabled || - !this.isGameRunning || - !this.lastLocation.playerList.size || - this.lastLocation.location === '' || - this.lastLocation.location === 'traveling' - ) { - return; - } - - var $location = parseLocation(this.lastLocation.location); - var instanceType = $location.accessType; - if (instanceType === 'group') { - if ($location.groupAccessType === 'members') { - instanceType = 'groupOnly'; - } else if ($location.groupAccessType === 'plus') { - instanceType = 'groupPlus'; - } else { - instanceType = 'groupPublic'; - } - } - if ( - this.autoStateChangeInstanceTypes.length > 0 && - !this.autoStateChangeInstanceTypes.includes(instanceType) - ) { - return; - } - - var withCompany = this.lastLocation.playerList.size > 1; - if (this.autoStateChangeNoFriends) { - withCompany = this.lastLocation.friendList.size >= 1; - } - - var currentStatus = API.currentUser.status; - var newStatus = withCompany - ? this.autoStateChangeCompanyStatus - : this.autoStateChangeAloneStatus; - - if (currentStatus === newStatus) { - return; - } - - userRequest - .saveCurrentUser({ - status: newStatus - }) - .then(() => { - var text = `Status automaticly changed to ${newStatus}`; - if (this.errorNoty) { - this.errorNoty.close(); - } - this.errorNoty = new Noty({ - type: 'info', - text - }).show(); - console.log(text); - }); - }; - - $app.methods.lookupUser = async function (ref) { - if (ref.userId) { - this.showUserDialog(ref.userId); - return; - } - if (!ref.displayName || ref.displayName.substring(0, 3) === 'ID:') { - return; - } - for (var ctx of API.cachedUsers.values()) { - if (ctx.displayName === ref.displayName) { - this.showUserDialog(ctx.id); - return; - } - } - this.searchText = ref.displayName; - await this.searchUserByDisplayName(ref.displayName); - for (var ctx of this.searchUserResults) { - if (ctx.displayName === ref.displayName) { - this.searchText = ''; - this.clearSearch(); - this.showUserDialog(ctx.id); - return; - } - } - // this.$refs.searchTab.currentName = '0'; - // this.menuActiveIndex = 'search'; - }; - - // #endregion - // #region | App: Search - - $app.data.searchText = ''; - $app.data.searchUserResults = []; - - API.$on('LOGIN', function () { - $app.searchText = ''; - $app.searchUserResults = []; - }); - - $app.methods.clearSearch = function () { - this.searchText = ''; - this.searchUserResults = []; - }; - - $app.methods.searchUserByDisplayName = async function (displayName) { - const params = { - n: 10, - offset: 0, - fuzzy: false, - search: displayName - }; - await this.moreSearchUser(null, params); - }; - - $app.methods.moreSearchUser = async function (go, params) { - // var params = this.searchUserParams; - if (go) { - params.offset += params.n * go; - if (params.offset < 0) { - params.offset = 0; - } - } - this.isSearchUserLoading = true; - await userRequest - .getUsers(params) - .finally(() => { - this.isSearchUserLoading = false; - }) - .then((args) => { - var map = new Map(); - for (var json of args.json) { - var ref = API.cachedUsers.get(json.id); - if (typeof ref !== 'undefined') { - map.set(ref.id, ref); - } - } - this.searchUserResults = Array.from(map.values()); - return args; - }); - }; - - // #endregion - // #region | App: Favorite - - $app.data.favoriteObjects = new Map(); - $app.data.favoriteFriends_ = []; - $app.data.favoriteFriendsSorted = []; - $app.data.favoriteWorlds_ = []; - $app.data.favoriteWorldsSorted = []; - $app.data.favoriteAvatars_ = []; - $app.data.favoriteAvatarsSorted = []; - $app.data.sortFavoriteFriends = false; - $app.data.sortFavoriteWorlds = false; - $app.data.sortFavoriteAvatars = false; - - API.$on('LOGIN', function () { - $app.favoriteObjects.clear(); - $app.favoriteFriends_ = []; - $app.favoriteFriendsSorted = []; - $app.favoriteWorlds_ = []; - $app.favoriteWorldsSorted = []; - $app.favoriteAvatars_ = []; - $app.favoriteAvatarsSorted = []; - $app.sortFavoriteFriends = false; - $app.sortFavoriteWorlds = false; - $app.sortFavoriteAvatars = false; - }); - - API.$on('FAVORITE', function (args) { - $app.applyFavorite(args.ref.type, args.ref.favoriteId, args.sortTop); - }); - - API.$on('FAVORITE:@DELETE', function (args) { - $app.applyFavorite(args.ref.type, args.ref.favoriteId); - }); - - API.$on('USER', function (args) { - $app.applyFavorite('friend', args.ref.id); - }); - - API.$on('WORLD', function (args) { - $app.applyFavorite('world', args.ref.id); - }); - - API.$on('AVATAR', function (args) { - $app.applyFavorite('avatar', args.ref.id); - }); - - $app.methods.applyFavorite = async function (type, objectId, sortTop) { - var favorite = API.cachedFavoritesByObjectId.get(objectId); - var ctx = this.favoriteObjects.get(objectId); - if (typeof favorite !== 'undefined') { - var isTypeChanged = false; - if (typeof ctx === 'undefined') { - ctx = { - id: objectId, - type, - groupKey: favorite.$groupKey, - ref: null, - name: '', - $selected: false - }; - this.favoriteObjects.set(objectId, ctx); - if (type === 'friend') { - var ref = API.cachedUsers.get(objectId); - if (typeof ref === 'undefined') { - ref = this.friendLog.get(objectId); - if (typeof ref !== 'undefined' && ref.displayName) { - ctx.name = ref.displayName; - } - } else { - ctx.ref = ref; - ctx.name = ref.displayName; - } - } else if (type === 'world') { - var ref = API.cachedWorlds.get(objectId); - if (typeof ref !== 'undefined') { - ctx.ref = ref; - ctx.name = ref.name; - } - } else if (type === 'avatar') { - var ref = API.cachedAvatars.get(objectId); - if (typeof ref !== 'undefined') { - ctx.ref = ref; - ctx.name = ref.name; - } - } - isTypeChanged = true; - } else { - if (ctx.type !== type) { - // WTF??? - isTypeChanged = true; - if (type === 'friend') { - $app.removeFromArray(this.favoriteFriends_, ctx); - $app.removeFromArray(this.favoriteFriendsSorted, ctx); - } else if (type === 'world') { - $app.removeFromArray(this.favoriteWorlds_, ctx); - $app.removeFromArray(this.favoriteWorldsSorted, ctx); - } else if (type === 'avatar') { - $app.removeFromArray(this.favoriteAvatars_, ctx); - $app.removeFromArray(this.favoriteAvatarsSorted, ctx); - } - } - if (type === 'friend') { - var ref = API.cachedUsers.get(objectId); - if (typeof ref !== 'undefined') { - if (ctx.ref !== ref) { - ctx.ref = ref; - } - if (ctx.name !== ref.displayName) { - ctx.name = ref.displayName; - this.sortFavoriteFriends = true; - } - } - // else too bad - } else if (type === 'world') { - var ref = API.cachedWorlds.get(objectId); - if (typeof ref !== 'undefined') { - if (ctx.ref !== ref) { - ctx.ref = ref; - } - if (ctx.name !== ref.name) { - ctx.name = ref.name; - this.sortFavoriteWorlds = true; - } - } else { - // try fetch from local world favorites - var world = await database.getCachedWorldById(objectId); - if (world) { - ctx.ref = world; - ctx.name = world.name; - ctx.deleted = true; - this.sortFavoriteWorlds = true; - } - if (!world) { - // try fetch from local world history - var worldName = - await database.getGameLogWorldNameByWorldId( - objectId - ); - if (worldName) { - ctx.name = worldName; - ctx.deleted = true; - this.sortFavoriteWorlds = true; - } - } - } - } else if (type === 'avatar') { - var ref = API.cachedAvatars.get(objectId); - if (typeof ref !== 'undefined') { - if (ctx.ref !== ref) { - ctx.ref = ref; - } - if (ctx.name !== ref.name) { - ctx.name = ref.name; - this.sortFavoriteAvatars = true; - } - } else { - // try fetch from local avatar history - var avatar = - await database.getCachedAvatarById(objectId); - if (avatar) { - ctx.ref = avatar; - ctx.name = avatar.name; - ctx.deleted = true; - this.sortFavoriteAvatars = true; - } - } - } - } - if (isTypeChanged) { - if (sortTop) { - if (type === 'friend') { - this.favoriteFriends_.unshift(ctx); - this.favoriteFriendsSorted.push(ctx); - this.sortFavoriteFriends = true; - } else if (type === 'world') { - this.favoriteWorlds_.unshift(ctx); - this.favoriteWorldsSorted.push(ctx); - this.sortFavoriteWorlds = true; - } else if (type === 'avatar') { - this.favoriteAvatars_.unshift(ctx); - this.favoriteAvatarsSorted.push(ctx); - this.sortFavoriteAvatars = true; - } - } else if (type === 'friend') { - this.favoriteFriends_.push(ctx); - this.favoriteFriendsSorted.push(ctx); - this.sortFavoriteFriends = true; - } else if (type === 'world') { - this.favoriteWorlds_.push(ctx); - this.favoriteWorldsSorted.push(ctx); - this.sortFavoriteWorlds = true; - } else if (type === 'avatar') { - this.favoriteAvatars_.push(ctx); - this.favoriteAvatarsSorted.push(ctx); - this.sortFavoriteAvatars = true; - } - } - } else if (typeof ctx !== 'undefined') { - this.favoriteObjects.delete(objectId); - if (type === 'friend') { - $app.removeFromArray(this.favoriteFriends_, ctx); - $app.removeFromArray(this.favoriteFriendsSorted, ctx); - } else if (type === 'world') { - $app.removeFromArray(this.favoriteWorlds_, ctx); - $app.removeFromArray(this.favoriteWorldsSorted, ctx); - } else if (type === 'avatar') { - $app.removeFromArray(this.favoriteAvatars_, ctx); - $app.removeFromArray(this.favoriteAvatarsSorted, ctx); - } - } - }; - - $app.methods.deleteFavoriteNoConfirm = function (objectId) { - if (!objectId) { - return; - } - this.favoriteDialog.visible = true; - favoriteRequest - .deleteFavorite({ - objectId - }) - .then(() => { - this.favoriteDialog.visible = false; - }) - .finally(() => { - this.favoriteDialog.loading = false; - }); - }; - - $app.computed.favoriteFriends = function () { - if (this.sortFavoriteFriends) { - this.sortFavoriteFriends = false; - this.favoriteFriendsSorted.sort($utils.compareByName); - } - if (this.sortFavorites) { - return this.favoriteFriends_; - } - return this.favoriteFriendsSorted; - }; - - $app.computed.groupedByGroupKeyFavoriteFriends = function () { - const groupedByGroupKeyFavoriteFriends = {}; - - this.favoriteFriends.forEach((friend) => { - if (friend.groupKey) { - if (!groupedByGroupKeyFavoriteFriends[friend.groupKey]) { - groupedByGroupKeyFavoriteFriends[friend.groupKey] = []; - } - groupedByGroupKeyFavoriteFriends[friend.groupKey].push(friend); - } - }); - - return groupedByGroupKeyFavoriteFriends; - }; - - $app.computed.favoriteWorlds = function () { - if (this.sortFavoriteWorlds) { - this.sortFavoriteWorlds = false; - this.favoriteWorldsSorted.sort($utils.compareByName); - } - if (this.sortFavorites) { - return this.favoriteWorlds_; - } - return this.favoriteWorldsSorted; - }; - - $app.computed.favoriteAvatars = function () { - if (this.sortFavoriteAvatars) { - this.sortFavoriteAvatars = false; - this.favoriteAvatarsSorted.sort($utils.compareByName); - } - if (this.sortFavorites) { - return this.favoriteAvatars_; - } - return this.favoriteAvatarsSorted; - }; - - // #endregion - // #region | App: friendLog - - $app.data.friendLog = new Map(); - $app.data.friendLogTable = { - data: [], - filters: [ - { - prop: 'type', - value: [], - filterFn: (row, filter) => - filter.value.some((v) => v === row.type) - }, - { - prop: 'displayName', - value: '' - }, - { - prop: 'type', - value: false, - filterFn: (row, filter) => - !(filter.value && row.type === 'Unfriend') - } - ], - tableProps: { - stripe: true, - size: 'mini', - defaultSort: { - prop: 'created_at', - order: 'descending' - } - }, - pageSize: $app.data.tablePageSize, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [10, 15, 20, 25, 50, 100] - } - }; - - API.$on('USER:CURRENT', function (args) { - $app.updateFriendships(args.ref); - }); - - API.$on('USER', function (args) { - $app.updateFriendship(args.ref); - if ( - $app.friendLogInitStatus && - args.json.isFriend && - !$app.friendLog.has(args.ref.id) && - args.json.id !== this.currentUser.id - ) { - $app.addFriendship(args.ref.id); - } - }); - - API.$on('FRIEND:ADD', function (args) { - $app.addFriendship(args.params.userId); - }); - - API.$on('FRIEND:DELETE', function (args) { - $app.deleteFriendship(args.params.userId); - }); - - $app.data.friendLogInitStatus = false; - $app.data.notificationInitStatus = false; - - $app.methods.initFriendLog = async function (currentUser) { - this.refreshFriends(currentUser, true); - var sqlValues = []; - var friends = await API.refreshFriends(); - for (var friend of friends) { - var ref = API.applyUser(friend); - var row = { - userId: ref.id, - displayName: ref.displayName, - trustLevel: ref.$trustLevel, - friendNumber: 0 - }; - this.friendLog.set(friend.id, row); - sqlValues.unshift(row); - } - database.setFriendLogCurrentArray(sqlValues); - await configRepository.setBool(`friendLogInit_${currentUser.id}`, true); - this.friendLogInitStatus = true; - }; - - $app.methods.migrateFriendLog = async function (userId) { - VRCXStorage.Remove(`${userId}_friendLogUpdatedAt`); - VRCXStorage.Remove(`${userId}_friendLog`); - this.friendLogTable.data = await VRCXStorage.GetArray( - `${userId}_friendLogTable` - ); - database.addFriendLogHistoryArray(this.friendLogTable.data); - VRCXStorage.Remove(`${userId}_friendLogTable`); - await configRepository.setBool(`friendLogInit_${userId}`, true); - }; - - $app.methods.getFriendLog = async function (currentUser) { - this.friendNumber = await configRepository.getInt( - `VRCX_friendNumber_${currentUser.id}`, - 0 - ); - var maxFriendLogNumber = await database.getMaxFriendLogNumber(); - if (this.friendNumber < maxFriendLogNumber) { - this.friendNumber = maxFriendLogNumber; - } - - var friendLogCurrentArray = await database.getFriendLogCurrent(); - for (var friend of friendLogCurrentArray) { - this.friendLog.set(friend.userId, friend); - } - this.friendLogTable.data = []; - this.friendLogTable.data = await database.getFriendLogHistory(); - this.refreshFriends(currentUser, true); - await API.refreshFriends(); - await this.tryRestoreFriendNumber(); - this.friendLogInitStatus = true; - - // check for friend/name/rank change AFTER friendLogInitStatus is set - for (var friend of friendLogCurrentArray) { - var ref = API.cachedUsers.get(friend.userId); - if (typeof ref !== 'undefined') { - this.updateFriendship(ref); - } - } - if (typeof currentUser.friends !== 'undefined') { - this.updateFriendships(currentUser); - } - }; - - $app.methods.addFriendship = function (id) { - if ( - !this.friendLogInitStatus || - this.friendLog.has(id) || - id === API.currentUser.id - ) { - return; - } - var ref = API.cachedUsers.get(id); - if (typeof ref === 'undefined') { - try { - userRequest.getUser({ - userId: id - }); - } catch (err) { - console.error('Fetch user on add as friend', err); - } - return; - } - friendRequest - .getFriendStatus({ - userId: id - }) - .then((args) => { - if (args.json.isFriend && !this.friendLog.has(id)) { - if (this.friendNumber === 0) { - this.friendNumber = this.friends.size; - } - ref.$friendNumber = ++this.friendNumber; - configRepository.setInt( - `VRCX_friendNumber_${API.currentUser.id}`, - this.friendNumber - ); - this.addFriend(id, ref.state); - var friendLogHistory = { - created_at: new Date().toJSON(), - type: 'Friend', - userId: id, - displayName: ref.displayName, - friendNumber: ref.$friendNumber - }; - this.friendLogTable.data.push(friendLogHistory); - database.addFriendLogHistory(friendLogHistory); - this.queueFriendLogNoty(friendLogHistory); - var friendLogCurrent = { - userId: id, - displayName: ref.displayName, - trustLevel: ref.$trustLevel, - friendNumber: ref.$friendNumber - }; - this.friendLog.set(id, friendLogCurrent); - database.setFriendLogCurrent(friendLogCurrent); - this.notifyMenu('friendLog'); - this.deleteFriendRequest(id); - this.updateSharedFeed(true); - userRequest - .getUser({ - userId: id - }) - .then(() => { - if ( - this.userDialog.visible && - id === this.userDialog.id - ) { - this.applyUserDialogLocation(true); - } - }); - } - }); - }; - - $app.methods.deleteFriendRequest = function (userId) { - var array = $app.notificationTable.data; - for (var i = array.length - 1; i >= 0; i--) { - if ( - array[i].type === 'friendRequest' && - array[i].senderUserId === userId - ) { - array.splice(i, 1); - return; - } - } - }; - - $app.methods.deleteFriendship = function (id) { - var ctx = this.friendLog.get(id); - if (typeof ctx === 'undefined') { - return; - } - friendRequest - .getFriendStatus({ - userId: id - }) - .then((args) => { - if (!args.json.isFriend && this.friendLog.has(id)) { - var friendLogHistory = { - created_at: new Date().toJSON(), - type: 'Unfriend', - userId: id, - displayName: ctx.displayName || id - }; - this.friendLogTable.data.push(friendLogHistory); - database.addFriendLogHistory(friendLogHistory); - this.queueFriendLogNoty(friendLogHistory); - this.friendLog.delete(id); - database.deleteFriendLogCurrent(id); - if (!this.hideUnfriends) { - this.notifyMenu('friendLog'); - } - this.updateSharedFeed(true); - this.deleteFriend(id); - } - }); - }; - - $app.methods.updateFriendships = function (ref) { - var set = new Set(); - for (var id of ref.friends) { - set.add(id); - this.addFriendship(id); - } - for (var id of this.friendLog.keys()) { - if (id === API.currentUser.id) { - this.friendLog.delete(id); - database.deleteFriendLogCurrent(id); - } else if (!set.has(id)) { - this.deleteFriendship(id); - } - } - }; - - $app.methods.updateFriendship = function (ref) { - var ctx = this.friendLog.get(ref.id); - if (!this.friendLogInitStatus || typeof ctx === 'undefined') { - return; - } - if (ctx.friendNumber) { - ref.$friendNumber = ctx.friendNumber; - } - if (!ref.$friendNumber) { - ref.$friendNumber = 0; // no null - } - if (ctx.displayName !== ref.displayName) { - if (ctx.displayName) { - var friendLogHistoryDisplayName = { - created_at: new Date().toJSON(), - type: 'DisplayName', - userId: ref.id, - displayName: ref.displayName, - previousDisplayName: ctx.displayName, - friendNumber: ref.$friendNumber - }; - this.friendLogTable.data.push(friendLogHistoryDisplayName); - database.addFriendLogHistory(friendLogHistoryDisplayName); - this.queueFriendLogNoty(friendLogHistoryDisplayName); - var friendLogCurrent = { - userId: ref.id, - displayName: ref.displayName, - trustLevel: ref.$trustLevel, - friendNumber: ref.$friendNumber - }; - this.friendLog.set(ref.id, friendLogCurrent); - database.setFriendLogCurrent(friendLogCurrent); - ctx.displayName = ref.displayName; - this.notifyMenu('friendLog'); - this.updateSharedFeed(true); - } - } - if ( - ref.$trustLevel && - ctx.trustLevel && - ctx.trustLevel !== ref.$trustLevel - ) { - if ( - (ctx.trustLevel === 'Trusted User' && - ref.$trustLevel === 'Veteran User') || - (ctx.trustLevel === 'Veteran User' && - ref.$trustLevel === 'Trusted User') - ) { - var friendLogCurrent3 = { - userId: ref.id, - displayName: ref.displayName, - trustLevel: ref.$trustLevel, - friendNumber: ref.$friendNumber - }; - this.friendLog.set(ref.id, friendLogCurrent3); - database.setFriendLogCurrent(friendLogCurrent3); - return; - } - var friendLogHistoryTrustLevel = { - created_at: new Date().toJSON(), - type: 'TrustLevel', - userId: ref.id, - displayName: ref.displayName, - trustLevel: ref.$trustLevel, - previousTrustLevel: ctx.trustLevel, - friendNumber: ref.$friendNumber - }; - this.friendLogTable.data.push(friendLogHistoryTrustLevel); - database.addFriendLogHistory(friendLogHistoryTrustLevel); - this.queueFriendLogNoty(friendLogHistoryTrustLevel); - var friendLogCurrent2 = { - userId: ref.id, - displayName: ref.displayName, - trustLevel: ref.$trustLevel, - friendNumber: ref.$friendNumber - }; - this.friendLog.set(ref.id, friendLogCurrent2); - database.setFriendLogCurrent(friendLogCurrent2); - this.notifyMenu('friendLog'); - this.updateSharedFeed(true); - } - ctx.trustLevel = ref.$trustLevel; - }; - - // #endregion - // #region | App: Moderation - - $app.data.playerModerationTable = { - data: [], - pageSize: $app.data.tablePageSize - }; - - API.$on('LOGIN', function () { - $app.playerModerationTable.data = []; - }); - - API.$on('PLAYER-MODERATION', function (args) { - let { ref } = args; - let array = $app.playerModerationTable.data; - let { length } = array; - for (let i = 0; i < length; ++i) { - if (array[i].id === ref.id) { - Vue.set(array, i, ref); - return; - } - } - $app.playerModerationTable.data.push(ref); - }); - - API.$on('PLAYER-MODERATION:@DELETE', function (args) { - let { ref } = args; - let array = $app.playerModerationTable.data; - let { length } = array; - for (let i = 0; i < length; ++i) { - if (array[i].id === ref.id) { - array.splice(i, 1); - return; - } - } - }); - - // #endregion - // #region | App: Notification - - $app.data.notificationTable = { - data: [], - filters: [ - { - prop: 'type', - value: [], - filterFn: (row, filter) => - filter.value.some((v) => v === row.type) - }, - { - prop: ['senderUsername', 'message'], - value: '' - } - ], - tableProps: { - stripe: true, - size: 'mini', - defaultSort: { - prop: 'created_at', - order: 'descending' - } - }, - pageSize: $app.data.tablePageSize, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [10, 15, 20, 25, 50, 100] - } - }; - - API.$on('LOGIN', function () { - $app.notificationTable.data = []; - }); - - API.$on('PIPELINE:NOTIFICATION', function (args) { - var ref = args.json; - if ( - ref.type !== 'requestInvite' || - $app.autoAcceptInviteRequests === 'Off' - ) { - return; - } - - var currentLocation = $app.lastLocation.location; - if ($app.lastLocation.location === 'traveling') { - currentLocation = $app.lastLocationDestination; - } - if (!currentLocation) { - return; - } - if ( - $app.autoAcceptInviteRequests === 'All Favorites' && - !$app.favoriteFriends.some((x) => x.id === ref.senderUserId) - ) { - return; - } - if ( - $app.autoAcceptInviteRequests === 'Selected Favorites' && - !$app.localFavoriteFriends.has(ref.senderUserId) - ) { - return; - } - if (!$app.checkCanInvite(currentLocation)) { - return; - } - - var L = parseLocation(currentLocation); - worldRequest - .getCachedWorld({ - worldId: L.worldId - }) - .then((args1) => { - notificationRequest - .sendInvite( - { - instanceId: L.tag, - worldId: L.tag, - worldName: args1.ref.name, - rsvp: true - }, - ref.senderUserId - ) - .then((_args) => { - var text = `Auto invite sent to ${ref.senderUsername}`; - if (this.errorNoty) { - this.errorNoty.close(); - } - this.errorNoty = new Noty({ - type: 'info', - text - }).show(); - console.log(text); - notificationRequest.hideNotification({ - notificationId: ref.id - }); - return _args; - }) - .catch((err) => { - console.error(err); - }); - }); - }); - - $app.data.unseenNotifications = []; - - API.$on('NOTIFICATION', function (args) { - var { ref } = args; - var array = $app.notificationTable.data; - var { length } = array; - for (var i = 0; i < length; ++i) { - if (array[i].id === ref.id) { - Vue.set(array, i, ref); - return; - } - } - if (ref.senderUserId !== this.currentUser.id) { - if ( - ref.type !== 'friendRequest' && - ref.type !== 'ignoredFriendRequest' && - !ref.type.includes('.') - ) { - database.addNotificationToDatabase(ref); - } - if ($app.friendLogInitStatus && $app.notificationInitStatus) { - if ( - $app.notificationTable.filters[0].value.length === 0 || - $app.notificationTable.filters[0].value.includes(ref.type) - ) { - $app.notifyMenu('notification'); - } - $app.unseenNotifications.push(ref.id); - $app.queueNotificationNoty(ref); - } - } - $app.notificationTable.data.push(ref); - $app.updateSharedFeed(true); - }); - - API.$on('NOTIFICATION:SEE', function (args) { - var { notificationId } = args.params; - $app.removeFromArray($app.unseenNotifications, notificationId); - if ($app.unseenNotifications.length === 0) { - const item = $app.$refs.menu.$children[0]?.items['notification']; - if (item) { - item.$el.classList.remove('notify'); - } - } - }); - - $app.data.feedTable.filter = JSON.parse( - await configRepository.getString('VRCX_feedTableFilters', '[]') - ); - $app.data.feedTable.vip = await configRepository.getBool( - 'VRCX_feedTableVIPFilter', - false - ); - $app.data.gameLogTable.vip = false; - // gameLog loads before favorites - // await configRepository.getBool( - // 'VRCX_gameLogTableVIPFilter', - // false - // ); - $app.data.gameLogTable.filter = JSON.parse( - await configRepository.getString('VRCX_gameLogTableFilters', '[]') - ); - $app.data.friendLogTable.filters[0].value = JSON.parse( - await configRepository.getString('VRCX_friendLogTableFilters', '[]') - ); - $app.data.notificationTable.filters[0].value = JSON.parse( - await configRepository.getString('VRCX_notificationTableFilters', '[]') - ); - $app.data.photonEventTableTypeFilter = JSON.parse( - await configRepository.getString('VRCX_photonEventTypeFilter', '[]') - ); - $app.data.photonEventTable.filters[1].value = - $app.data.photonEventTableTypeFilter; - $app.data.photonEventTablePrevious.filters[1].value = - $app.data.photonEventTableTypeFilter; - $app.data.photonEventTableTypeOverlayFilter = JSON.parse( - await configRepository.getString( - 'VRCX_photonEventTypeOverlayFilter', - '[]' - ) - ); - - // #endregion - // #region | App: Profile + Settings - - $app.data.pastDisplayNameTable = { - data: [], - tableProps: { - stripe: true, - size: 'mini', - defaultSort: { - prop: 'updated_at', - order: 'descending' - } - }, - layout: 'table' - }; - $app.data.printTable = []; - $app.data.stickerTable = []; - $app.data.emojiTable = []; - $app.data.VRCPlusIconsTable = []; - $app.data.galleryTable = []; - $app.data.inviteMessageTable = { - data: [], - tableProps: { - stripe: true, - size: 'mini' - }, - layout: 'table', - visible: false - }; - $app.data.inviteResponseMessageTable = { - data: [], - tableProps: { - stripe: true, - size: 'mini' - }, - layout: 'table', - visible: false - }; - $app.data.inviteRequestMessageTable = { - data: [], - tableProps: { - stripe: true, - size: 'mini' - }, - layout: 'table', - visible: false - }; - $app.data.inviteRequestResponseMessageTable = { - data: [], - tableProps: { - stripe: true, - size: 'mini' - }, - layout: 'table', - visible: false - }; - $app.data.currentInstanceUserList = { - data: [], - tableProps: { - stripe: true, - size: 'mini', - defaultSort: { - prop: 'timer', - order: 'descending' - } - }, - layout: 'table' - }; - $app.data.visits = 0; - $app.data.openVR = await configRepository.getBool('openVR', false); - $app.data.openVRAlways = await configRepository.getBool( - 'openVRAlways', - false - ); - $app.data.overlaybutton = await configRepository.getBool( - 'VRCX_overlaybutton', - false - ); - $app.data.overlayHand = await configRepository.getInt( - 'VRCX_overlayHand', - 0 - ); - $app.data.hidePrivateFromFeed = await configRepository.getBool( - 'VRCX_hidePrivateFromFeed', - false - ); - $app.data.hideDevicesFromFeed = await configRepository.getBool( - 'VRCX_hideDevicesFromFeed', - false - ); - $app.data.vrOverlayCpuUsage = await configRepository.getBool( - 'VRCX_vrOverlayCpuUsage', - false - ); - $app.data.hideUptimeFromFeed = await configRepository.getBool( - 'VRCX_hideUptimeFromFeed', - false - ); - $app.data.pcUptimeOnFeed = await configRepository.getBool( - 'VRCX_pcUptimeOnFeed', - false - ); - $app.data.overlayNotifications = await configRepository.getBool( - 'VRCX_overlayNotifications', - true - ); - $app.data.overlayWrist = await configRepository.getBool( - 'VRCX_overlayWrist', - false - ); - $app.data.xsNotifications = await configRepository.getBool( - 'VRCX_xsNotifications', - true - ); - $app.data.ovrtHudNotifications = await configRepository.getBool( - 'VRCX_ovrtHudNotifications', - true - ); - $app.data.ovrtWristNotifications = await configRepository.getBool( - 'VRCX_ovrtWristNotifications', - false - ); - $app.data.imageNotifications = await configRepository.getBool( - 'VRCX_imageNotifications', - true - ); - $app.data.desktopToast = await configRepository.getString( - 'VRCX_desktopToast', - 'Never' - ); - $app.data.afkDesktopToast = await configRepository.getBool( - 'VRCX_afkDesktopToast', - false - ); - $app.data.overlayToast = await configRepository.getString( - 'VRCX_overlayToast', - 'Game Running' - ); - $app.data.minimalFeed = await configRepository.getBool( - 'VRCX_minimalFeed', - false - ); - $app.data.displayVRCPlusIconsAsAvatar = await configRepository.getBool( - 'displayVRCPlusIconsAsAvatar', - true - ); - $app.data.hideTooltips = await configRepository.getBool( - 'VRCX_hideTooltips', - false - ); - $app.data.hideNicknames = await configRepository.getBool( - 'VRCX_hideNicknames', - false - ); - $app.data.notificationTTS = await configRepository.getString( - 'VRCX_notificationTTS', - 'Never' - ); - $app.data.notificationTTSNickName = await configRepository.getBool( - 'VRCX_notificationTTSNickName', - false - ); - $app.data.notificationOpacity = await configRepository.getFloat( - 'VRCX_notificationOpacity', - 100 - ); - - // It's not necessary to store it in configRepo because it's rarely used. - $app.data.isTestTTSVisible = false; - - $app.data.notificationTTSVoice = await configRepository.getString( - 'VRCX_notificationTTSVoice', - '0' - ); - $app.data.notificationTimeout = await configRepository.getString( - 'VRCX_notificationTimeout', - '3000' - ); - $app.data.autoSweepVRChatCache = await configRepository.getBool( - 'VRCX_autoSweepVRChatCache', - false - ); - $app.data.relaunchVRChatAfterCrash = await configRepository.getBool( - 'VRCX_relaunchVRChatAfterCrash', - false - ); - $app.data.vrcQuitFix = await configRepository.getBool( - 'VRCX_vrcQuitFix', - true - ); - $app.data.vrBackgroundEnabled = await configRepository.getBool( - 'VRCX_vrBackgroundEnabled', - false - ); - $app.data.asideWidth = await configRepository.getInt( - 'VRCX_sidePanelWidth', - 300 - ); - $app.data.autoUpdateVRCX = await configRepository.getString( - 'VRCX_autoUpdateVRCX', - 'Auto Download' - ); - if ($app.data.autoUpdateVRCX === 'Auto Install') { - $app.data.autoUpdateVRCX = 'Auto Download'; - } - $app.data.branch = await configRepository.getString( - 'VRCX_branch', - 'Stable' - ); - $app.data.maxTableSize = await configRepository.getInt( - 'VRCX_maxTableSize', - 1000 - ); - if ($app.data.maxTableSize > 10000) { - $app.data.maxTableSize = 1000; - } - database.setmaxTableSize($app.data.maxTableSize); - $app.data.photonLobbyTimeoutThreshold = await configRepository.getInt( - 'VRCX_photonLobbyTimeoutThreshold', - 6000 - ); - $app.data.clearVRCXCacheFrequency = await configRepository.getInt( - 'VRCX_clearVRCXCacheFrequency', - 172800 - ); - $app.data.avatarRemoteDatabase = await configRepository.getBool( - 'VRCX_avatarRemoteDatabase', - true - ); - $app.data.avatarRemoteDatabaseProvider = ''; - $app.data.avatarRemoteDatabaseProviderList = JSON.parse( - await configRepository.getString( - 'VRCX_avatarRemoteDatabaseProviderList', - '[ "https://api.avtrdb.com/v2/avatar/search/vrcx", "https://avtr.just-h.party/vrcx_search.php" ]' - ) - ); - if ( - $app.data.avatarRemoteDatabaseProviderList.length === 1 && - $app.data.avatarRemoteDatabaseProviderList[0] === - 'https://avtr.just-h.party/vrcx_search.php' - ) { - $app.data.avatarRemoteDatabaseProviderList.unshift( - 'https://api.avtrdb.com/v2/avatar/search/vrcx' - ); - await configRepository.setString( - 'VRCX_avatarRemoteDatabaseProviderList', - JSON.stringify($app.data.avatarRemoteDatabaseProviderList) - ); - } - $app.data.pendingOfflineDelay = 180000; - - // It's a mess, but it'll be fine afterward with the state manager - $app.data.isAgeGatedInstancesVisible = await configRepository.getBool( - 'VRCX_isAgeGatedInstancesVisible', - true - ); - - $app.methods.toggleIsAgeGatedInstancesVisible = function () { - this.isAgeGatedInstancesVisible = !this.isAgeGatedInstancesVisible; - configRepository.setBool( - 'VRCX_isAgeGatedInstancesVisible', - this.isAgeGatedInstancesVisible - ); - }; - - if (await configRepository.getString('VRCX_avatarRemoteDatabaseProvider')) { - // move existing provider to new list - var avatarRemoteDatabaseProvider = await configRepository.getString( - 'VRCX_avatarRemoteDatabaseProvider' - ); - if ( - !$app.data.avatarRemoteDatabaseProviderList.includes( - avatarRemoteDatabaseProvider - ) - ) { - $app.data.avatarRemoteDatabaseProviderList.push( - avatarRemoteDatabaseProvider - ); - } - await configRepository.remove('VRCX_avatarRemoteDatabaseProvider'); - await configRepository.setString( - 'VRCX_avatarRemoteDatabaseProviderList', - JSON.stringify($app.data.avatarRemoteDatabaseProviderList) - ); - } - if ($app.data.avatarRemoteDatabaseProviderList.length > 0) { - $app.data.avatarRemoteDatabaseProvider = - $app.data.avatarRemoteDatabaseProviderList[0]; - } - $app.data.sortFavorites = await configRepository.getBool( - 'VRCX_sortFavorites', - true - ); - $app.data.randomUserColours = await configRepository.getBool( - 'VRCX_randomUserColours', - false - ); - $app.data.hideUserNotes = await configRepository.getBool( - 'VRCX_hideUserNotes', - false - ); - $app.data.hideUserMemos = await configRepository.getBool( - 'VRCX_hideUserMemos', - false - ); - $app.data.hideUnfriends = await configRepository.getBool( - 'VRCX_hideUnfriends', - false - ); - $app.data.friendLogTable.filters[2].value = $app.data.hideUnfriends; - $app.methods.saveOpenVROption = async function (configKey = '') { - switch (configKey) { - case 'openVR': - this.openVR = !this.openVR; - break; - case 'VRCX_hidePrivateFromFeed': - this.hidePrivateFromFeed = !this.hidePrivateFromFeed; - break; - case 'VRCX_hideDevicesFromFeed': - this.hideDevicesFromFeed = !this.hideDevicesFromFeed; - break; - case 'VRCX_vrOverlayCpuUsage': - this.vrOverlayCpuUsage = !this.vrOverlayCpuUsage; - break; - case 'VRCX_hideUptimeFromFeed': - this.hideUptimeFromFeed = !this.hideUptimeFromFeed; - break; - case 'VRCX_pcUptimeOnFeed': - this.pcUptimeOnFeed = !this.pcUptimeOnFeed; - break; - case 'VRCX_overlayNotifications': - this.overlayNotifications = !this.overlayNotifications; - break; - case 'VRCX_overlayWrist': - this.overlayWrist = !this.overlayWrist; - break; - case 'VRCX_xsNotifications': - this.xsNotifications = !this.xsNotifications; - break; - case 'VRCX_ovrtHudNotifications': - this.ovrtHudNotifications = !this.ovrtHudNotifications; - break; - case 'VRCX_ovrtWristNotifications': - this.ovrtWristNotifications = !this.ovrtWristNotifications; - break; - case 'VRCX_imageNotifications': - this.imageNotifications = !this.imageNotifications; - break; - case 'VRCX_afkDesktopToast': - this.afkDesktopToast = !this.afkDesktopToast; - break; - case 'VRCX_notificationTTSNickName': - this.notificationTTSNickName = !this.notificationTTSNickName; - break; - case 'VRCX_minimalFeed': - this.minimalFeed = !this.minimalFeed; - break; - case 'displayVRCPlusIconsAsAvatar': - this.displayVRCPlusIconsAsAvatar = - !this.displayVRCPlusIconsAsAvatar; - break; - case 'VRCX_hideTooltips': - this.hideTooltips = !this.hideTooltips; - break; - case 'VRCX_hideNicknames': - this.hideNicknames = !this.hideNicknames; - break; - case 'VRCX_autoSweepVRChatCache': - this.autoSweepVRChatCache = !this.autoSweepVRChatCache; - break; - case 'VRCX_relaunchVRChatAfterCrash': - this.relaunchVRChatAfterCrash = !this.relaunchVRChatAfterCrash; - break; - case 'VRCX_vrcQuitFix': - this.vrcQuitFix = !this.vrcQuitFix; - break; - case 'VRCX_vrBackgroundEnabled': - this.vrBackgroundEnabled = !this.vrBackgroundEnabled; - break; - case 'VRCX_avatarRemoteDatabase': - this.avatarRemoteDatabase = !this.avatarRemoteDatabase; - break; - case 'VRCX_udonExceptionLogging': - this.udonExceptionLogging = !this.udonExceptionLogging; - break; - case 'VRCX_autoDeleteOldPrints': - this.autoDeleteOldPrints = !this.autoDeleteOldPrints; - break; - default: - break; - } - - await configRepository.setBool('openVR', this.openVR); - - await configRepository.setBool('openVRAlways', this.openVRAlways); - await configRepository.setBool( - 'VRCX_overlaybutton', - this.overlaybutton - ); - this.overlayHand = parseInt(this.overlayHand, 10); - if (isNaN(this.overlayHand)) { - this.overlayHand = 0; - } - await configRepository.setInt('VRCX_overlayHand', this.overlayHand); - - await configRepository.setBool( - 'VRCX_hidePrivateFromFeed', - this.hidePrivateFromFeed - ); - - await configRepository.setBool( - 'VRCX_hideDevicesFromFeed', - this.hideDevicesFromFeed - ); - - await configRepository.setBool( - 'VRCX_vrOverlayCpuUsage', - this.vrOverlayCpuUsage - ); - - await configRepository.setBool( - 'VRCX_hideUptimeFromFeed', - this.hideUptimeFromFeed - ); - - await configRepository.setBool( - 'VRCX_pcUptimeOnFeed', - this.pcUptimeOnFeed - ); - - await configRepository.setBool( - 'VRCX_overlayNotifications', - this.overlayNotifications - ); - - await configRepository.setBool('VRCX_overlayWrist', this.overlayWrist); - - await configRepository.setBool( - 'VRCX_xsNotifications', - this.xsNotifications - ); - - await configRepository.setBool( - 'VRCX_ovrtHudNotifications', - this.ovrtHudNotifications - ); - - await configRepository.setBool( - 'VRCX_ovrtWristNotifications', - this.ovrtWristNotifications - ); - - await configRepository.setBool( - 'VRCX_imageNotifications', - this.imageNotifications - ); - - await configRepository.setString( - 'VRCX_desktopToast', - this.desktopToast - ); - - await configRepository.setBool( - 'VRCX_afkDesktopToast', - this.afkDesktopToast - ); - - await configRepository.setString( - 'VRCX_overlayToast', - this.overlayToast - ); - - await configRepository.setBool( - 'VRCX_notificationTTSNickName', - this.notificationTTSNickName - ); - - await configRepository.setBool('VRCX_minimalFeed', this.minimalFeed); - - await configRepository.setBool( - 'displayVRCPlusIconsAsAvatar', - this.displayVRCPlusIconsAsAvatar - ); - - await configRepository.setBool('VRCX_hideTooltips', this.hideTooltips); - - await configRepository.setBool( - 'VRCX_hideNicknames', - this.hideNicknames - ); - - await configRepository.setBool( - 'VRCX_autoSweepVRChatCache', - this.autoSweepVRChatCache - ); - - await configRepository.setBool( - 'VRCX_relaunchVRChatAfterCrash', - this.relaunchVRChatAfterCrash - ); - - await configRepository.setBool('VRCX_vrcQuitFix', this.vrcQuitFix); - - await configRepository.setBool( - 'VRCX_vrBackgroundEnabled', - this.vrBackgroundEnabled - ); - - await configRepository.setBool( - 'VRCX_avatarRemoteDatabase', - this.avatarRemoteDatabase - ); - - await configRepository.setBool( - 'VRCX_instanceUsersSortAlphabetical', - this.instanceUsersSortAlphabetical - ); - - await configRepository.setBool( - 'VRCX_randomUserColours', - this.randomUserColours - ); - - await configRepository.setBool( - 'VRCX_udonExceptionLogging', - this.udonExceptionLogging - ); - - await configRepository.setBool( - 'VRCX_autoDeleteOldPrints', - this.autoDeleteOldPrints - ); - - await configRepository.setInt( - 'VRCX_notificationOpacity', - this.notificationOpacity - ); - - this.updateSharedFeed(true); - this.updateVRConfigVars(); - this.updateVRLastLocation(); - AppApi.ExecuteVrOverlayFunction('notyClear', ''); - this.updateOpenVR(); - }; - - $app.methods.saveSortFavoritesOption = async function () { - this.getLocalWorldFavorites(); - await configRepository.setBool( - 'VRCX_sortFavorites', - this.sortFavorites - ); - }; - - $app.methods.saveUserDialogOption = async function (configKey = '') { - if (configKey === 'VRCX_hideUserNotes') { - this.hideUserNotes = !this.hideUserNotes; - } else { - this.hideUserMemos = !this.hideUserMemos; - } - - await configRepository.setBool( - 'VRCX_hideUserNotes', - this.hideUserNotes - ); - await configRepository.setBool( - 'VRCX_hideUserMemos', - this.hideUserMemos - ); - }; - - $app.methods.saveFriendLogOptions = async function () { - // The function is only called in adv settings - this.hideUnfriends = !this.hideUnfriends; - await configRepository.setBool( - 'VRCX_hideUnfriends', - this.hideUnfriends - ); - this.friendLogTable.filters[2].value = this.hideUnfriends; - }; - $app.data.notificationTTSTest = ''; - $app.data.TTSvoices = speechSynthesis.getVoices(); - $app.methods.updateTTSVoices = function () { - this.TTSvoices = speechSynthesis.getVoices(); - if (LINUX) { - let voices = speechSynthesis.getVoices(); - let uniqueVoices = []; - voices.forEach((voice) => { - if (!uniqueVoices.some((v) => v.lang === voice.lang)) { - uniqueVoices.push(voice); - } - }); - uniqueVoices = uniqueVoices.filter((v) => v.lang.startsWith('en')); - this.TTSvoices = uniqueVoices; - } - }; - $app.methods.saveNotificationTTS = async function () { - speechSynthesis.cancel(); - if ( - (await configRepository.getString('VRCX_notificationTTS')) === - 'Never' && - this.notificationTTS !== 'Never' - ) { - this.speak('Notification text-to-speech enabled'); - } - await configRepository.setString( - 'VRCX_notificationTTS', - this.notificationTTS - ); - this.updateVRConfigVars(); - }; - $app.methods.testNotificationTTS = function () { - speechSynthesis.cancel(); - this.speak(this.notificationTTSTest); - }; - $app.data.themeMode = await configRepository.getString( - 'VRCX_ThemeMode', - 'system' - ); - - $app.data.isDarkMode = false; - - $app.methods.systemIsDarkMode = function () { - return window.matchMedia('(prefers-color-scheme: dark)').matches; - }; - - window - .matchMedia('(prefers-color-scheme: dark)') - .addEventListener('change', async () => { - if ($app.themeMode === 'system') { - await $app.changeThemeMode(); - } - }); - - $app.methods.saveThemeMode = async function (newThemeMode) { - this.themeMode = newThemeMode; - await configRepository.setString('VRCX_ThemeMode', this.themeMode); - await this.changeThemeMode(); - }; - - $app.methods.changeThemeMode = async function () { - if ( - document.contains(document.getElementById('app-theme-dark-style')) - ) { - document.getElementById('app-theme-dark-style').remove(); - } - if (document.contains(document.getElementById('app-theme-style'))) { - document.getElementById('app-theme-style').remove(); - } - var $appThemeStyle = document.createElement('link'); - $appThemeStyle.setAttribute('id', 'app-theme-style'); - $appThemeStyle.rel = 'stylesheet'; - switch (this.themeMode) { - case 'light': - $appThemeStyle.href = ''; - this.isDarkMode = false; - break; - case 'dark': - $appThemeStyle.href = ''; - this.isDarkMode = true; - break; - case 'darkvanillaold': - $appThemeStyle.href = 'theme.darkvanillaold.css'; - this.isDarkMode = true; - break; - case 'darkvanilla': - $appThemeStyle.href = 'theme.darkvanilla.css'; - this.isDarkMode = true; - break; - case 'pink': - $appThemeStyle.href = 'theme.pink.css'; - this.isDarkMode = true; - break; - case 'material3': - $appThemeStyle.href = 'theme.material3.css'; - this.isDarkMode = true; - break; - case 'system': - this.isDarkMode = this.systemIsDarkMode(); - break; - } - if (this.isDarkMode) { - AppApi.ChangeTheme(1); - var $appThemeDarkStyle = document.createElement('link'); - $appThemeDarkStyle.setAttribute('id', 'app-theme-dark-style'); - $appThemeDarkStyle.rel = 'stylesheet'; - $appThemeDarkStyle.href = 'theme.dark.css'; - document.head.appendChild($appThemeDarkStyle); - } else { - AppApi.ChangeTheme(0); - } - if ($appThemeStyle.href) { - document.head.appendChild($appThemeStyle); - } - this.updateVRConfigVars(); - await this.updateTrustColor(); - await this.applyWineEmojis(); - }; - - $app.methods.applyWineEmojis = async function () { - if (document.contains(document.getElementById('app-emoji-font'))) { - document.getElementById('app-emoji-font').remove(); - } - if (this.isRunningUnderWine) { - var $appEmojiFont = document.createElement('link'); - $appEmojiFont.setAttribute('id', 'app-emoji-font'); - $appEmojiFont.rel = 'stylesheet'; - $appEmojiFont.href = 'emoji.font.css'; - document.head.appendChild($appEmojiFont); - } - }; - - $app.data.isStartAtWindowsStartup = await configRepository.getBool( - 'VRCX_StartAtWindowsStartup', - false - ); - $app.data.isStartAsMinimizedState = - (await VRCXStorage.Get('VRCX_StartAsMinimizedState')) === 'true'; - $app.data.isCloseToTray = - (await VRCXStorage.Get('VRCX_CloseToTray')) === 'true'; - if (await configRepository.getBool('VRCX_CloseToTray')) { - // move back to JSON - $app.data.isCloseToTray = - await configRepository.getBool('VRCX_CloseToTray'); - VRCXStorage.Set('VRCX_CloseToTray', $app.data.isCloseToTray.toString()); - await configRepository.remove('VRCX_CloseToTray'); - } - if (!(await VRCXStorage.Get('VRCX_DatabaseLocation'))) { - await VRCXStorage.Set('VRCX_DatabaseLocation', ''); - } - if (!(await VRCXStorage.Get('VRCX_ProxyServer'))) { - await VRCXStorage.Set('VRCX_ProxyServer', ''); - } - if ((await VRCXStorage.Get('VRCX_DisableGpuAcceleration')) === '') { - await VRCXStorage.Set('VRCX_DisableGpuAcceleration', 'false'); - } - if ( - (await VRCXStorage.Get('VRCX_DisableVrOverlayGpuAcceleration')) === '' - ) { - await VRCXStorage.Set('VRCX_DisableVrOverlayGpuAcceleration', 'false'); - } - $app.data.proxyServer = await VRCXStorage.Get('VRCX_ProxyServer'); - $app.data.disableGpuAcceleration = - (await VRCXStorage.Get('VRCX_DisableGpuAcceleration')) === 'true'; - $app.data.locationX = await VRCXStorage.Get('VRCX_LocationX'); - $app.data.locationY = await VRCXStorage.Get('VRCX_LocationY'); - $app.data.sizeWidth = await VRCXStorage.Get('VRCX_SizeWidth'); - $app.data.sizeHeight = await VRCXStorage.Get('VRCX_SizeHeight'); - $app.data.windowState = await VRCXStorage.Get('VRCX_WindowState'); - $app.data.disableVrOverlayGpuAcceleration = - (await VRCXStorage.Get('VRCX_DisableVrOverlayGpuAcceleration')) === - 'true'; - $app.data.disableWorldDatabase = - (await VRCXStorage.Get('VRCX_DisableWorldDatabase')) === 'true'; - - $app.methods.saveVRCXWindowOption = async function (configKey = '') { - switch (configKey) { - case 'VRCX_StartAtWindowsStartup': - this.isStartAtWindowsStartup = !this.isStartAtWindowsStartup; - break; - case 'VRCX_saveInstancePrints': - this.saveInstancePrints = !this.saveInstancePrints; - break; - case 'VRCX_cropInstancePrints': - this.cropInstancePrints = !this.cropInstancePrints; - this.cropPrintsChanged(); - break; - case 'VRCX_saveInstanceStickers': - this.saveInstanceStickers = !this.saveInstanceStickers; - break; - case 'VRCX_saveInstanceEmoji': - this.saveInstanceEmoji = !this.saveInstanceEmoji; - break; - case 'VRCX_StartAsMinimizedState': - this.isStartAsMinimizedState = !this.isStartAsMinimizedState; - break; - case 'VRCX_CloseToTray': - this.isCloseToTray = !this.isCloseToTray; - break; - case 'VRCX_DisableWorldDatabase': - this.disableWorldDatabase = !this.disableWorldDatabase; - break; - case 'VRCX_DisableGpuAcceleration': - this.disableGpuAcceleration = !this.disableGpuAcceleration; - break; - case 'VRCX_DisableVrOverlayGpuAcceleration': - this.disableVrOverlayGpuAcceleration = - !this.disableVrOverlayGpuAcceleration; - break; - default: - break; - } - - await configRepository.setBool( - 'VRCX_StartAtWindowsStartup', - this.isStartAtWindowsStartup - ); - - await configRepository.setBool( - 'VRCX_saveInstancePrints', - this.saveInstancePrints - ); - - await configRepository.setBool( - 'VRCX_cropInstancePrints', - this.cropInstancePrints - ); - - await configRepository.setBool( - 'VRCX_saveInstanceStickers', - this.saveInstanceStickers - ); - - await configRepository.setBool( - 'VRCX_saveInstanceEmoji', - this.saveInstanceEmoji - ); - - VRCXStorage.Set( - 'VRCX_StartAsMinimizedState', - this.isStartAsMinimizedState.toString() - ); - - VRCXStorage.Set('VRCX_CloseToTray', this.isCloseToTray.toString()); - - VRCXStorage.Set( - 'VRCX_DisableWorldDatabase', - this.disableWorldDatabase.toString() - ); - - VRCXStorage.Set( - 'VRCX_DisableGpuAcceleration', - this.disableGpuAcceleration.toString() - ); - VRCXStorage.Set( - 'VRCX_DisableVrOverlayGpuAcceleration', - this.disableVrOverlayGpuAcceleration.toString() - ); - - if (LINUX) { - VRCXStorage.Set('VRCX_LocationX', this.locationX); - VRCXStorage.Set('VRCX_LocationY', this.locationY); - VRCXStorage.Set('VRCX_SizeWidth', this.sizeWidth); - VRCXStorage.Set('VRCX_SizeHeight', this.sizeHeight); - VRCXStorage.Set('VRCX_WindowState', this.windowState); - VRCXStorage.Flush(); - } else { - AppApi.SetStartup(this.isStartAtWindowsStartup); - } - }; - - $app.data.photonEventOverlay = await configRepository.getBool( - 'VRCX_PhotonEventOverlay', - false - ); - $app.data.timeoutHudOverlay = await configRepository.getBool( - 'VRCX_TimeoutHudOverlay', - false - ); - $app.data.timeoutHudOverlayFilter = await configRepository.getString( - 'VRCX_TimeoutHudOverlayFilter', - 'Everyone' - ); - $app.data.photonEventOverlayFilter = await configRepository.getString( - 'VRCX_PhotonEventOverlayFilter', - 'Everyone' - ); - $app.data.photonOverlayMessageTimeout = Number( - await configRepository.getString( - 'VRCX_photonOverlayMessageTimeout', - 6000 - ) - ); - $app.data.gameLogDisabled = await configRepository.getBool( - 'VRCX_gameLogDisabled', - false - ); - $app.data.udonExceptionLogging = await configRepository.getBool( - 'VRCX_udonExceptionLogging', - false - ); - $app.data.instanceUsersSortAlphabetical = await configRepository.getBool( - 'VRCX_instanceUsersSortAlphabetical', - false - ); - $app.methods.saveEventOverlay = async function (configKey = '') { - if (configKey === 'VRCX_PhotonEventOverlay') { - this.photonEventOverlay = !this.photonEventOverlay; - } else if (configKey === 'VRCX_TimeoutHudOverlay') { - this.timeoutHudOverlay = !this.timeoutHudOverlay; - } - await configRepository.setBool( - 'VRCX_PhotonEventOverlay', - this.photonEventOverlay - ); - await configRepository.setBool( - 'VRCX_TimeoutHudOverlay', - this.timeoutHudOverlay - ); - await configRepository.setString( - 'VRCX_TimeoutHudOverlayFilter', - this.timeoutHudOverlayFilter - ); - await configRepository.setString( - 'VRCX_PhotonEventOverlayFilter', - this.photonEventOverlayFilter - ); - if (!this.timeoutHudOverlay) { - AppApi.ExecuteVrOverlayFunction('updateHudTimeout', '[]'); - } - this.updateOpenVR(); - this.updateVRConfigVars(); - }; - $app.data.logResourceLoad = await configRepository.getBool( - 'VRCX_logResourceLoad', - false - ); - $app.data.logEmptyAvatars = await configRepository.getBool( - 'VRCX_logEmptyAvatars', - false - ); - $app.methods.saveLoggingOptions = async function (configKey = '') { - if (configKey === 'VRCX_logResourceLoad') { - this.logResourceLoad = !this.logResourceLoad; - } else { - this.logEmptyAvatars = !this.logEmptyAvatars; - } - - await configRepository.setBool( - 'VRCX_logResourceLoad', - this.logResourceLoad - ); - await configRepository.setBool( - 'VRCX_logEmptyAvatars', - this.logEmptyAvatars - ); - }; - $app.data.autoStateChangeEnabled = await configRepository.getBool( - 'VRCX_autoStateChangeEnabled', - false - ); - $app.data.autoStateChangeNoFriends = await configRepository.getBool( - 'VRCX_autoStateChangeNoFriends', - false - ); - $app.data.autoStateChangeInstanceTypes = JSON.parse( - await configRepository.getString( - 'VRCX_autoStateChangeInstanceTypes', - '[]' - ) - ); - $app.data.autoStateChangeAloneStatus = await configRepository.getString( - 'VRCX_autoStateChangeAloneStatus', - 'join me' - ); - $app.data.autoStateChangeCompanyStatus = await configRepository.getString( - 'VRCX_autoStateChangeCompanyStatus', - 'busy' - ); - $app.data.autoAcceptInviteRequests = await configRepository.getString( - 'VRCX_autoAcceptInviteRequests', - 'Off' - ); - $app.methods.saveAutomationOptions = async function (configKey = '') { - if (configKey === 'VRCX_autoStateChangeEnabled') { - this.autoStateChangeEnabled = !this.autoStateChangeEnabled; - await configRepository.setBool( - 'VRCX_autoStateChangeEnabled', - this.autoStateChangeEnabled - ); - } - await configRepository.setBool( - 'VRCX_autoStateChangeNoFriends', - this.autoStateChangeNoFriends - ); - await configRepository.setString( - 'VRCX_autoStateChangeInstanceTypes', - JSON.stringify(this.autoStateChangeInstanceTypes) - ); - await configRepository.setString( - 'VRCX_autoStateChangeAloneStatus', - this.autoStateChangeAloneStatus - ); - await configRepository.setString( - 'VRCX_autoStateChangeCompanyStatus', - this.autoStateChangeCompanyStatus - ); - await configRepository.setString( - 'VRCX_autoAcceptInviteRequests', - this.autoAcceptInviteRequests - ); - }; - - $app.data.isRegistryBackupDialogVisible = false; - - $app.methods.showRegistryBackupDialog = function () { - this.isRegistryBackupDialogVisible = true; - }; - - $app.data.sidebarSortMethod1 = ''; - $app.data.sidebarSortMethod2 = ''; - $app.data.sidebarSortMethod3 = ''; - $app.data.sidebarSortMethods = JSON.parse( - await configRepository.getString( - 'VRCX_sidebarSortMethods', - JSON.stringify([ - 'Sort Private to Bottom', - 'Sort by Time in Instance', - 'Sort by Last Active' - ]) - ) - ); - if ($app.data.sidebarSortMethods?.length === 3) { - $app.data.sidebarSortMethod1 = $app.data.sidebarSortMethods[0]; - $app.data.sidebarSortMethod2 = $app.data.sidebarSortMethods[1]; - $app.data.sidebarSortMethod3 = $app.data.sidebarSortMethods[2]; - } - - // Migrate old settings - // Assume all exist if one does - const orderFriendsGroupPrivate = await configRepository.getBool( - 'orderFriendGroupPrivate' - ); - if (orderFriendsGroupPrivate !== null) { - await configRepository.remove('orderFriendGroupPrivate'); - - const orderFriendsGroupStatus = await configRepository.getBool( - 'orderFriendsGroupStatus' - ); - await configRepository.remove('orderFriendsGroupStatus'); - - const orderFriendsGroupGPS = await configRepository.getBool( - 'orderFriendGroupGPS' - ); - await configRepository.remove('orderFriendGroupGPS'); - - const orderOnlineFor = - await configRepository.getBool('orderFriendGroup0'); - await configRepository.remove('orderFriendGroup0'); - await configRepository.remove('orderFriendGroup1'); - await configRepository.remove('orderFriendGroup2'); - await configRepository.remove('orderFriendGroup3'); - - var sortOrder = []; - if (orderFriendsGroupPrivate) { - sortOrder.push('Sort Private to Bottom'); - } - if (orderFriendsGroupStatus) { - sortOrder.push('Sort by Status'); - } - if (orderOnlineFor && orderFriendsGroupGPS) { - sortOrder.push('Sort by Time in Instance'); - } - if (!orderOnlineFor) { - sortOrder.push('Sort Alphabetically'); - } - - if (sortOrder.length > 0) { - while (sortOrder.length < 3) { - sortOrder.push(''); - } - $app.data.sidebarSortMethods = sortOrder; - $app.data.sidebarSortMethod1 = sortOrder[0]; - $app.data.sidebarSortMethod2 = sortOrder[1]; - $app.data.sidebarSortMethod3 = sortOrder[2]; - } - await configRepository.setString( - 'VRCX_sidebarSortMethods', - JSON.stringify(sortOrder) - ); - } - - $app.methods.saveSidebarSortOrder = async function () { - if (this.sidebarSortMethod1 === this.sidebarSortMethod2) { - this.sidebarSortMethod2 = ''; - } - if (this.sidebarSortMethod1 === this.sidebarSortMethod3) { - this.sidebarSortMethod3 = ''; - } - if (this.sidebarSortMethod2 === this.sidebarSortMethod3) { - this.sidebarSortMethod3 = ''; - } - if (!this.sidebarSortMethod1) { - this.sidebarSortMethod2 = ''; - } - if (!this.sidebarSortMethod2) { - this.sidebarSortMethod3 = ''; - } - this.sidebarSortMethods = [ - this.sidebarSortMethod1, - this.sidebarSortMethod2, - this.sidebarSortMethod3 - ]; - await configRepository.setString( - 'VRCX_sidebarSortMethods', - JSON.stringify(this.sidebarSortMethods) - ); - this.sortVIPFriends = true; - this.sortOnlineFriends = true; - this.sortActiveFriends = true; - this.sortOfflineFriends = true; - }; - $app.data.discordActive = await configRepository.getBool( - 'discordActive', - false - ); - $app.data.discordInstance = await configRepository.getBool( - 'discordInstance', - true - ); - $app.data.discordJoinButton = await configRepository.getBool( - 'discordJoinButton', - false - ); - $app.data.discordHideInvite = await configRepository.getBool( - 'discordHideInvite', - true - ); - $app.data.discordHideImage = await configRepository.getBool( - 'discordHideImage', - false - ); - - // setting defaults - $app.data.sharedFeedFiltersDefaults = { - noty: { - Location: 'Off', - OnPlayerJoined: 'VIP', - OnPlayerLeft: 'VIP', - OnPlayerJoining: 'VIP', - Online: 'VIP', - Offline: 'VIP', - GPS: 'Off', - Status: 'Off', - invite: 'Friends', - requestInvite: 'Friends', - inviteResponse: 'Friends', - requestInviteResponse: 'Friends', - friendRequest: 'On', - Friend: 'On', - Unfriend: 'On', - DisplayName: 'VIP', - TrustLevel: 'VIP', - boop: 'Off', - groupChange: 'On', - 'group.announcement': 'On', - 'group.informative': 'On', - 'group.invite': 'On', - 'group.joinRequest': 'Off', - 'group.transfer': 'On', - 'group.queueReady': 'On', - 'instance.closed': 'On', - PortalSpawn: 'Everyone', - Event: 'On', - External: 'On', - VideoPlay: 'Off', - BlockedOnPlayerJoined: 'Off', - BlockedOnPlayerLeft: 'Off', - MutedOnPlayerJoined: 'Off', - MutedOnPlayerLeft: 'Off', - AvatarChange: 'Off', - ChatBoxMessage: 'Off', - Blocked: 'Off', - Unblocked: 'Off', - Muted: 'Off', - Unmuted: 'Off' - }, - wrist: { - Location: 'On', - OnPlayerJoined: 'Everyone', - OnPlayerLeft: 'Everyone', - OnPlayerJoining: 'Friends', - Online: 'Friends', - Offline: 'Friends', - GPS: 'Friends', - Status: 'Friends', - invite: 'Friends', - requestInvite: 'Friends', - inviteResponse: 'Friends', - requestInviteResponse: 'Friends', - friendRequest: 'On', - Friend: 'On', - Unfriend: 'On', - DisplayName: 'Friends', - TrustLevel: 'Friends', - boop: 'On', - groupChange: 'On', - 'group.announcement': 'On', - 'group.informative': 'On', - 'group.invite': 'On', - 'group.joinRequest': 'On', - 'group.transfer': 'On', - 'group.queueReady': 'On', - 'instance.closed': 'On', - PortalSpawn: 'Everyone', - Event: 'On', - External: 'On', - VideoPlay: 'On', - BlockedOnPlayerJoined: 'Off', - BlockedOnPlayerLeft: 'Off', - MutedOnPlayerJoined: 'Off', - MutedOnPlayerLeft: 'Off', - AvatarChange: 'Everyone', - ChatBoxMessage: 'Off', - Blocked: 'On', - Unblocked: 'On', - Muted: 'On', - Unmuted: 'On' - } - }; - $app.data.sharedFeedFilters = $app.data.sharedFeedFiltersDefaults; - if (await configRepository.getString('sharedFeedFilters')) { - $app.data.sharedFeedFilters = JSON.parse( - await configRepository.getString( - 'sharedFeedFilters', - JSON.stringify($app.data.sharedFeedFiltersDefaults) - ) - ); - } - if (!$app.data.sharedFeedFilters.noty.Blocked) { - $app.data.sharedFeedFilters.noty.Blocked = 'Off'; - $app.data.sharedFeedFilters.noty.Unblocked = 'Off'; - $app.data.sharedFeedFilters.noty.Muted = 'Off'; - $app.data.sharedFeedFilters.noty.Unmuted = 'Off'; - $app.data.sharedFeedFilters.wrist.Blocked = 'On'; - $app.data.sharedFeedFilters.wrist.Unblocked = 'On'; - $app.data.sharedFeedFilters.wrist.Muted = 'On'; - $app.data.sharedFeedFilters.wrist.Unmuted = 'On'; - } - if (!$app.data.sharedFeedFilters.noty['group.announcement']) { - $app.data.sharedFeedFilters.noty['group.announcement'] = 'On'; - $app.data.sharedFeedFilters.noty['group.informative'] = 'On'; - $app.data.sharedFeedFilters.noty['group.invite'] = 'On'; - $app.data.sharedFeedFilters.noty['group.joinRequest'] = 'Off'; - $app.data.sharedFeedFilters.wrist['group.announcement'] = 'On'; - $app.data.sharedFeedFilters.wrist['group.informative'] = 'On'; - $app.data.sharedFeedFilters.wrist['group.invite'] = 'On'; - $app.data.sharedFeedFilters.wrist['group.joinRequest'] = 'On'; - } - if (!$app.data.sharedFeedFilters.noty['group.queueReady']) { - $app.data.sharedFeedFilters.noty['group.queueReady'] = 'On'; - $app.data.sharedFeedFilters.wrist['group.queueReady'] = 'On'; - } - if (!$app.data.sharedFeedFilters.noty['instance.closed']) { - $app.data.sharedFeedFilters.noty['instance.closed'] = 'On'; - $app.data.sharedFeedFilters.wrist['instance.closed'] = 'On'; - } - if (!$app.data.sharedFeedFilters.noty.External) { - $app.data.sharedFeedFilters.noty.External = 'On'; - $app.data.sharedFeedFilters.wrist.External = 'On'; - } - if (!$app.data.sharedFeedFilters.noty.groupChange) { - $app.data.sharedFeedFilters.noty.groupChange = 'On'; - $app.data.sharedFeedFilters.wrist.groupChange = 'On'; - } - if (!$app.data.sharedFeedFilters.noty['group.transfer']) { - $app.data.sharedFeedFilters.noty['group.transfer'] = 'On'; - $app.data.sharedFeedFilters.wrist['group.transfer'] = 'On'; - } - if (!$app.data.sharedFeedFilters.noty.boop) { - $app.data.sharedFeedFilters.noty.boop = 'Off'; - $app.data.sharedFeedFilters.wrist.boop = 'On'; - } - - $app.data.trustColor = JSON.parse( - await configRepository.getString( - 'VRCX_trustColor', - JSON.stringify({ - untrusted: '#CCCCCC', - basic: '#1778FF', - known: '#2BCF5C', - trusted: '#FF7B42', - veteran: '#B18FFF', - vip: '#FF2626', - troll: '#782F2F' - }) - ) - ); - - $app.methods.updateTrustColor = async function (setRandomColor = false) { - if (setRandomColor) { - this.randomUserColours = !this.randomUserColours; - } - if (typeof API.currentUser?.id === 'undefined') { - return; - } - await configRepository.setBool( - 'VRCX_randomUserColours', - this.randomUserColours - ); - await configRepository.setString( - 'VRCX_trustColor', - JSON.stringify(this.trustColor) - ); - if (this.randomUserColours) { - this.getNameColour(API.currentUser.id).then((colour) => { - API.currentUser.$userColour = colour; - }); - this.userColourInit(); - } else { - API.applyUserTrustLevel(API.currentUser); - API.cachedUsers.forEach((ref) => { - API.applyUserTrustLevel(ref); - }); - } - await this.updateTrustColorClasses(); - }; - - $app.methods.updateTrustColorClasses = async function () { - var trustColor = JSON.parse( - await configRepository.getString( - 'VRCX_trustColor', - JSON.stringify({ - untrusted: '#CCCCCC', - basic: '#1778FF', - known: '#2BCF5C', - trusted: '#FF7B42', - veteran: '#B18FFF', - vip: '#FF2626', - troll: '#782F2F' - }) - ) - ); - if (document.getElementById('trustColor') !== null) { - document.getElementById('trustColor').outerHTML = ''; - } - var style = document.createElement('style'); - style.id = 'trustColor'; - style.type = 'text/css'; - var newCSS = ''; - for (var rank in trustColor) { - newCSS += `.x-tag-${rank} { color: ${trustColor[rank]} !important; border-color: ${trustColor[rank]} !important; } `; - } - style.innerHTML = newCSS; - document.getElementsByTagName('head')[0].appendChild(style); - }; - await $app.methods.updateTrustColorClasses(); - - $app.data.notificationPosition = await configRepository.getString( - 'VRCX_notificationPosition', - 'topCenter' - ); - $app.methods.changeNotificationPosition = async function (value) { - this.notificationPosition = value; - await configRepository.setString( - 'VRCX_notificationPosition', - this.notificationPosition - ); - this.updateVRConfigVars(); - }; - - $app.data.youTubeApi = await configRepository.getBool( - 'VRCX_youtubeAPI', - false - ); - $app.data.youTubeApiKey = await configRepository.getString( - 'VRCX_youtubeAPIKey', - '' - ); - - $app.data.progressPie = await configRepository.getBool( - 'VRCX_progressPie', - false - ); - $app.data.progressPieFilter = await configRepository.getBool( - 'VRCX_progressPieFilter', - true - ); - - $app.data.screenshotHelper = await configRepository.getBool( - 'VRCX_screenshotHelper', - true - ); - - $app.data.screenshotHelperModifyFilename = await configRepository.getBool( - 'VRCX_screenshotHelperModifyFilename', - false - ); - - $app.data.screenshotHelperCopyToClipboard = await configRepository.getBool( - 'VRCX_screenshotHelperCopyToClipboard', - false - ); - - $app.data.enableAppLauncher = await configRepository.getBool( - 'VRCX_enableAppLauncher', - true - ); - - $app.data.enableAppLauncherAutoClose = await configRepository.getBool( - 'VRCX_enableAppLauncherAutoClose', - true - ); - - $app.data.showConfirmationOnSwitchAvatar = await configRepository.getBool( - 'VRCX_showConfirmationOnSwitchAvatar', - false - ); - - $app.methods.updateVRConfigVars = function () { - var notificationTheme = 'relax'; - if (this.isDarkMode) { - notificationTheme = 'sunset'; - } - var VRConfigVars = { - overlayNotifications: this.overlayNotifications, - hideDevicesFromFeed: this.hideDevicesFromFeed, - vrOverlayCpuUsage: this.vrOverlayCpuUsage, - minimalFeed: this.minimalFeed, - notificationPosition: this.notificationPosition, - notificationTimeout: this.notificationTimeout, - photonOverlayMessageTimeout: this.photonOverlayMessageTimeout, - notificationTheme, - backgroundEnabled: this.vrBackgroundEnabled, - dtHour12: this.dtHour12, - pcUptimeOnFeed: this.pcUptimeOnFeed, - appLanguage: this.appLanguage, - notificationOpacity: this.notificationOpacity - }; - var json = JSON.stringify(VRConfigVars); - AppApi.ExecuteVrFeedFunction('configUpdate', json); - AppApi.ExecuteVrOverlayFunction('configUpdate', json); - }; - - $app.methods.isRpcWorld = function (location) { - var rpcWorlds = [ - 'wrld_f20326da-f1ac-45fc-a062-609723b097b1', - 'wrld_42377cf1-c54f-45ed-8996-5875b0573a83', - 'wrld_dd6d2888-dbdc-47c2-bc98-3d631b2acd7c', - 'wrld_52bdcdab-11cd-4325-9655-0fb120846945', - 'wrld_2d40da63-8f1f-4011-8a9e-414eb8530acd', - 'wrld_10e5e467-fc65-42ed-8957-f02cace1398c', - 'wrld_04899f23-e182-4a8d-b2c7-2c74c7c15534', - 'wrld_435bbf25-f34f-4b8b-82c6-cd809057eb8e', - 'wrld_db9d878f-6e76-4776-8bf2-15bcdd7fc445', - 'wrld_f767d1c8-b249-4ecc-a56f-614e433682c8', - 'wrld_74970324-58e8-4239-a17b-2c59dfdf00db', - 'wrld_266523e8-9161-40da-acd0-6bd82e075833' - ]; - var L = parseLocation(location); - if (rpcWorlds.includes(L.worldId)) { - return true; - } - return false; - }; - - $app.methods.updateVRLastLocation = function () { - var progressPie = false; - if (this.progressPie) { - progressPie = true; - if (this.progressPieFilter) { - if (!this.isRpcWorld(this.lastLocation.location)) { - progressPie = false; - } - } - } - var onlineFor = ''; - if (!this.hideUptimeFromFeed) { - onlineFor = API.currentUser.$online_for; - } - var lastLocation = { - date: this.lastLocation.date, - location: this.lastLocation.location, - name: this.lastLocation.name, - playerList: Array.from(this.lastLocation.playerList.values()), - friendList: Array.from(this.lastLocation.friendList.values()), - progressPie, - onlineFor - }; - var json = JSON.stringify(lastLocation); - AppApi.ExecuteVrFeedFunction('lastLocationUpdate', json); - AppApi.ExecuteVrOverlayFunction('lastLocationUpdate', json); - }; - - $app.methods.vrInit = function () { - this.updateVRConfigVars(); - this.updateVRLastLocation(); - this.updateVrNowPlaying(); - this.updateSharedFeed(true); - this.onlineFriendCount = 0; - this.updateOnlineFriendCoutner(); - }; - - API.$on('LOGIN', function () { - $app.pastDisplayNameTable.data = []; - }); - - API.$on('USER:CURRENT', function (args) { - if (args.ref.pastDisplayNames) { - $app.pastDisplayNameTable.data = args.ref.pastDisplayNames; - } - }); - - $app.methods.updateOpenVR = function () { - if ( - this.openVR && - this.isSteamVRRunning && - ((this.isGameRunning && !this.isGameNoVR) || this.openVRAlways) - ) { - var hmdOverlay = false; - if ( - this.overlayNotifications || - this.progressPie || - this.photonEventOverlay || - this.timeoutHudOverlay - ) { - hmdOverlay = true; - } - // active, hmdOverlay, wristOverlay, menuButton, overlayHand - AppApi.SetVR( - true, - hmdOverlay, - this.overlayWrist, - this.overlaybutton, - this.overlayHand - ); - } else { - AppApi.SetVR(false, false, false, false, 0); - } - }; - - $app.methods.getTTSVoiceName = function () { - var voices; - if (LINUX) { - voices = this.TTSvoices; - } else { - voices = speechSynthesis.getVoices(); - } - if (voices.length === 0) { - return ''; - } - if (this.notificationTTSVoice >= voices.length) { - this.notificationTTSVoice = 0; - configRepository.setString( - 'VRCX_notificationTTSVoice', - this.notificationTTSVoice - ); - } - return voices[this.notificationTTSVoice].name; - }; - - $app.methods.changeTTSVoice = async function (index) { - this.notificationTTSVoice = index; - await configRepository.setString( - 'VRCX_notificationTTSVoice', - this.notificationTTSVoice - ); - var voices; - if (LINUX) { - voices = this.TTSvoices; - } else { - voices = speechSynthesis.getVoices(); - } - if (voices.length === 0) { - return; - } - var voiceName = voices[index].name; - speechSynthesis.cancel(); - this.speak(voiceName); - }; - - $app.methods.speak = function (text) { - var tts = new SpeechSynthesisUtterance(); - var voices = speechSynthesis.getVoices(); - if (voices.length === 0) { - return; - } - var index = 0; - if (this.notificationTTSVoice < voices.length) { - index = this.notificationTTSVoice; - } - tts.voice = voices[index]; - tts.text = text; - speechSynthesis.speak(tts); - }; - - $app.methods.directAccessPaste = function () { - AppApi.GetClipboard().then((clipboard) => { - if (!this.directAccessParse(clipboard.trim())) { - this.promptOmniDirectDialog(); - } - }); - }; - - $app.methods.directAccessWorld = function (textBoxInput) { - var input = textBoxInput; - if (input.startsWith('/home/')) { - input = `https://vrchat.com${input}`; - } - if (input.length === 8) { - return this.verifyShortName('', input); - } else if (input.startsWith('https://vrch.at/')) { - var shortName = input.substring(16, 24); - return this.verifyShortName('', shortName); - } else if ( - input.startsWith('https://vrchat.') || - input.startsWith('/home/') - ) { - var url = new URL(input); - var urlPath = url.pathname; - var urlPathSplit = urlPath.split('/'); - if (urlPathSplit.length >= 4 && urlPathSplit[2] === 'world') { - var worldId = urlPathSplit[3]; - this.showWorldDialog(worldId); - return true; - } else if (urlPath.substring(5, 12) === '/launch') { - var urlParams = new URLSearchParams(url.search); - var worldId = urlParams.get('worldId'); - var instanceId = urlParams.get('instanceId'); - if (instanceId) { - var shortName = urlParams.get('shortName'); - var location = `${worldId}:${instanceId}`; - if (shortName) { - return this.verifyShortName(location, shortName); - } - this.showWorldDialog(location); - return true; - } else if (worldId) { - this.showWorldDialog(worldId); - return true; - } - } - } else if (input.substring(0, 5) === 'wrld_') { - // a bit hacky, but supports weird malformed inputs cut out from url, why not - if (input.indexOf('&instanceId=') >= 0) { - input = `https://vrchat.com/home/launch?worldId=${input}`; - return this.directAccessWorld(input); - } - this.showWorldDialog(input.trim()); - return true; - } - return false; - }; - - $app.methods.verifyShortName = function (location, shortName) { - return instanceRequest - .getInstanceFromShortName({ shortName }) - .then((args) => { - var newLocation = args.json.location; - var newShortName = args.json.shortName; - if (newShortName) { - this.showWorldDialog(newLocation, newShortName); - } else if (newLocation) { - this.showWorldDialog(newLocation); - } else { - this.showWorldDialog(location); - } - return args; - }); - }; - - $app.methods.showGroupDialogShortCode = function (shortCode) { - groupRequest.groupStrictsearch({ query: shortCode }).then((args) => { - for (const group of args.json) { - if (`${group.shortCode}.${group.discriminator}` === shortCode) { - this.showGroupDialog(group.id); - break; - } - } - return args; - }); - }; - - $app.methods.directAccessParse = function (input) { - if (!input) { - return false; - } - if (this.directAccessWorld(input)) { - return true; - } - if (input.startsWith('https://vrchat.')) { - var url = new URL(input); - var urlPath = url.pathname; - var urlPathSplit = urlPath.split('/'); - if (urlPathSplit.length < 4) { - return false; - } - var type = urlPathSplit[2]; - if (type === 'user') { - var userId = urlPathSplit[3]; - this.showUserDialog(userId); - return true; - } else if (type === 'avatar') { - var avatarId = urlPathSplit[3]; - this.showAvatarDialog(avatarId); - return true; - } else if (type === 'group') { - var groupId = urlPathSplit[3]; - this.showGroupDialog(groupId); - return true; - } - } else if (input.startsWith('https://vrc.group/')) { - var shortCode = input.substring(18); - this.showGroupDialogShortCode(shortCode); - return true; - } else if (/^[A-Za-z0-9]{3,6}\.[0-9]{4}$/g.test(input)) { - this.showGroupDialogShortCode(input); - return true; - } else if ( - input.substring(0, 4) === 'usr_' || - /^[A-Za-z0-9]{10}$/g.test(input) - ) { - this.showUserDialog(input); - return true; - } else if (input.substring(0, 5) === 'avtr_') { - this.showAvatarDialog(input); - return true; - } else if (input.substring(0, 4) === 'grp_') { - this.showGroupDialog(input); - return true; - } - return false; - }; - - $app.methods.setTablePageSize = async function (pageSize) { - this.tablePageSize = pageSize; - this.feedTable.pageSize = pageSize; - this.gameLogTable.pageSize = pageSize; - this.friendLogTable.pageSize = pageSize; - this.playerModerationTable.pageSize = pageSize; - this.notificationTable.pageSize = pageSize; - await configRepository.setInt('VRCX_tablePageSize', pageSize); - }; - - // #endregion - // #region | App: Dialog - - $app.methods.adjustDialogZ = function (el) { - var z = 0; - document - .querySelectorAll('.v-modal,.el-dialog__wrapper') - .forEach((v) => { - var _z = Number(v.style.zIndex) || 0; - if (_z && _z > z && v !== el) { - z = _z; - } - }); - if (z) { - el.style.zIndex = z + 1; - } - }; - - // #endregion - // #region | App: User Dialog - - $app.data.userDialog = { - visible: false, - loading: false, - id: '', - ref: {}, - friend: {}, - isFriend: false, - note: '', - noteSaving: false, - incomingRequest: false, - outgoingRequest: false, - isBlock: false, - isMute: false, - isHideAvatar: false, - isShowAvatar: false, - isInteractOff: false, - isMuteChat: false, - isFavorite: false, - - $location: {}, - $homeLocationName: '', - users: [], - instance: {}, - - worlds: [], - avatars: [], - isWorldsLoading: false, - isFavoriteWorldsLoading: false, - isAvatarsLoading: false, - isGroupsLoading: false, - - worldSorting: { - name: $t('dialog.user.worlds.sorting.updated'), - value: 'updated' - }, - worldOrder: { - name: $t('dialog.user.worlds.order.descending'), - value: 'descending' - }, - // because userDialogGroupSortingOptions, just i18n key - groupSorting: { - name: 'dialog.user.groups.sorting.alphabetical', - value: 'alphabetical' - }, - avatarSorting: 'update', - avatarReleaseStatus: 'all', - - treeData: [], - memo: '', - $avatarInfo: { - ownerId: '', - avatarName: '', - fileCreatedAt: '' - }, - representedGroup: { - bannerUrl: '', - description: '', - discriminator: '', - groupId: '', - iconUrl: '', - isRepresenting: false, - memberCount: 0, - memberVisibility: '', - name: '', - ownerId: '', - privacy: '', - shortCode: '', - $thumbnailUrl: '' - }, - isRepresentedGroupLoading: false, - joinCount: 0, - timeSpent: 0, - lastSeen: '', - avatarModeration: 0, - previousDisplayNames: [], - dateFriended: '', - unFriended: false, - dateFriendedInfo: [] - }; - - API.$on('LOGOUT', function () { - $app.userDialog.visible = false; - }); - - API.$on('USER', function (args) { - var { ref } = args; - var D = $app.userDialog; - if (D.visible === false || D.id !== ref.id) { - return; - } - D.ref = ref; - D.note = String(ref.note || ''); - D.noteSaving = false; - D.incomingRequest = false; - D.outgoingRequest = false; - if (D.ref.friendRequestStatus === 'incoming') { - D.incomingRequest = true; - } else if (D.ref.friendRequestStatus === 'outgoing') { - D.outgoingRequest = true; - } - }); - - API.$on('USER', function (args) { - // refresh user dialog JSON tab - if ( - !$app.userDialog.visible || - $app.userDialog.id !== args.ref.id || - $app.$refs.userDialogTabs?.currentName !== '5' - ) { - return; - } - $app.refreshUserDialogTreeData(); - }); - - API.$on('WORLD', function (args) { - var D = $app.userDialog; - if (D.visible === false || D.$location.worldId !== args.ref.id) { - return; - } - $app.applyUserDialogLocation(); - }); - - API.$on('FRIEND:STATUS', function (args) { - var D = $app.userDialog; - if (D.visible === false || D.id !== args.params.userId) { - return; - } - var { json } = args; - D.isFriend = json.isFriend; - D.incomingRequest = json.incomingRequest; - D.outgoingRequest = json.outgoingRequest; - }); - - API.$on('FRIEND:REQUEST:CANCEL', function (args) { - var D = $app.userDialog; - if (D.visible === false || D.id !== args.params.userId) { - return; - } - D.outgoingRequest = false; - }); - - API.$on('NOTIFICATION', function (args) { - var { ref } = args; - var D = $app.userDialog; - if ( - D.visible === false || - ref.$isDeleted || - ref.type !== 'friendRequest' || - ref.senderUserId !== D.id - ) { - return; - } - D.incomingRequest = true; - }); - - API.$on('NOTIFICATION:ACCEPT', function (args) { - var { ref } = args; - var D = $app.userDialog; - // 얘는 @DELETE가 오고나서 ACCEPT가 옴 - // 따라서 $isDeleted라면 ref가 undefined가 됨 - if ( - D.visible === false || - typeof ref === 'undefined' || - ref.type !== 'friendRequest' || - ref.senderUserId !== D.id - ) { - return; - } - D.isFriend = true; - }); - - API.$on('NOTIFICATION:EXPIRE', function (args) { - var { ref } = args; - var D = $app.userDialog; - if ( - D.visible === false || - ref.type !== 'friendRequest' || - ref.senderUserId !== D.id - ) { - return; - } - D.incomingRequest = false; - }); - - API.$on('FRIEND:DELETE', function (args) { - var D = $app.userDialog; - if (D.visible === false || D.id !== args.params.userId) { - return; - } - D.isFriend = false; - }); - - API.$on('PLAYER-MODERATION:@SEND', function (args) { - var { ref } = args; - var D = $app.userDialog; - if ( - D.visible === false || - (ref.targetUserId !== D.id && - ref.sourceUserId !== this.currentUser.id) - ) { - return; - } - if (ref.type === 'block') { - D.isBlock = true; - } else if (ref.type === 'mute') { - D.isMute = true; - } else if (ref.type === 'hideAvatar') { - D.isHideAvatar = true; - } else if (ref.type === 'interactOff') { - D.isInteractOff = true; - } else if (ref.type === 'muteChat') { - D.isMuteChat = true; - } - $app.$message({ - message: $t('message.user.moderated'), - type: 'success' - }); - }); - - API.$on('PLAYER-MODERATION:@DELETE', function (args) { - var { ref } = args; - var D = $app.userDialog; - if ( - D.visible === false || - ref.targetUserId !== D.id || - ref.sourceUserId !== this.currentUser.id - ) { - return; - } - if (ref.type === 'block') { - D.isBlock = false; - } else if (ref.type === 'mute') { - D.isMute = false; - } else if (ref.type === 'hideAvatar') { - D.isHideAvatar = false; - } else if (ref.type === 'interactOff') { - D.isInteractOff = false; - } else if (ref.type === 'muteChat') { - D.isMuteChat = false; - } - }); - - API.$on('FAVORITE', function (args) { - var { ref } = args; - var D = $app.userDialog; - if (D.visible === false || ref.$isDeleted || ref.favoriteId !== D.id) { - return; - } - D.isFavorite = true; - }); - - API.$on('FAVORITE:@DELETE', function (args) { - var D = $app.userDialog; - if (D.visible === false || D.id !== args.ref.favoriteId) { - return; - } - D.isFavorite = false; - }); - - $app.methods.showUserDialog = function (userId) { - if (!userId) { - return; - } - const D = this.userDialog; - D.id = userId; - D.treeData = []; - D.memo = ''; - D.note = ''; - D.noteSaving = false; - this.getUserMemo(userId).then((memo) => { - if (memo.userId === userId) { - D.memo = memo.memo; - const ref = this.friends.get(userId); - if (ref) { - ref.memo = String(memo.memo || ''); - if (memo.memo) { - ref.$nickName = memo.memo.split('\n')[0]; - } else { - ref.$nickName = ''; - } - } - } - }); - D.visible = true; - D.loading = true; - D.avatars = []; - D.worlds = []; - D.instance = { - id: '', - tag: '', - $location: {}, - friendCount: 0, - users: [], - shortName: '', - ref: {} - }; - D.isRepresentedGroupLoading = true; - D.representedGroup = { - bannerUrl: '', - description: '', - discriminator: '', - groupId: '', - iconUrl: '', - isRepresenting: false, - memberCount: 0, - memberVisibility: '', - name: '', - ownerId: '', - privacy: '', - shortCode: '', - $thumbnailUrl: '' - }; - D.lastSeen = ''; - D.joinCount = 0; - D.timeSpent = 0; - D.avatarModeration = 0; - D.isHideAvatar = false; - D.isShowAvatar = false; - D.previousDisplayNames = []; - D.dateFriended = ''; - D.unFriended = false; - D.dateFriendedInfo = []; - if (userId === API.currentUser.id) { - this.getWorldName(API.currentUser.homeLocation).then( - (worldName) => { - D.$homeLocationName = worldName; - } - ); - } - AppApi.SendIpc('ShowUserDialog', userId); - userRequest - .getCachedUser({ - userId - }) - .catch((err) => { - D.loading = false; - D.visible = false; - this.$message({ - message: 'Failed to load user', - type: 'error' - }); - throw err; - }) - .then((args) => { - if (args.ref.id === D.id) { - requestAnimationFrame(() => { - D.ref = args.ref; - D.friend = this.friends.get(D.id); - D.isFriend = Boolean(D.friend); - D.note = String(D.ref.note || ''); - D.incomingRequest = false; - D.outgoingRequest = false; - D.isBlock = false; - D.isMute = false; - D.isInteractOff = false; - D.isMuteChat = false; - for (const ref of API.cachedPlayerModerations.values()) { - if ( - ref.targetUserId === D.id && - ref.sourceUserId === API.currentUser.id - ) { - if (ref.type === 'block') { - D.isBlock = true; - } else if (ref.type === 'mute') { - D.isMute = true; - } else if (ref.type === 'hideAvatar') { - D.isHideAvatar = true; - } else if (ref.type === 'interactOff') { - D.isInteractOff = true; - } else if (ref.type === 'muteChat') { - D.isMuteChat = true; - } - } - } - D.isFavorite = API.cachedFavoritesByObjectId.has(D.id); - if (D.ref.friendRequestStatus === 'incoming') { - D.incomingRequest = true; - } else if (D.ref.friendRequestStatus === 'outgoing') { - D.outgoingRequest = true; - } - this.applyUserDialogLocation(true); - - if (args.cache) { - userRequest.getUser(args.params); - } - let inCurrentWorld = false; - if (this.lastLocation.playerList.has(D.ref.id)) { - inCurrentWorld = true; - } - if (userId !== API.currentUser.id) { - database - .getUserStats(D.ref, inCurrentWorld) - .then((ref1) => { - if (ref1.userId === D.id) { - D.lastSeen = ref1.lastSeen; - D.joinCount = ref1.joinCount; - D.timeSpent = ref1.timeSpent; - } - let displayNameMap = - ref1.previousDisplayNames; - this.friendLogTable.data.forEach((ref2) => { - if (ref2.userId === D.id) { - if (ref2.type === 'DisplayName') { - displayNameMap.set( - ref2.previousDisplayName, - ref2.created_at - ); - } - if (!D.dateFriended) { - if (ref2.type === 'Unfriend') { - D.unFriended = true; - if (!this.hideUnfriends) { - D.dateFriended = - ref2.created_at; - } - } - if (ref2.type === 'Friend') { - D.unFriended = false; - D.dateFriended = - ref2.created_at; - } - } - if ( - ref2.type === 'Friend' || - (ref2.type === 'Unfriend' && - !this.hideUnfriends) - ) { - D.dateFriendedInfo.push(ref2); - } - } - }); - const displayNameMapSorted = new Map( - [...displayNameMap.entries()].sort( - (a, b) => b[1] - a[1] - ) - ); - D.previousDisplayNames = Array.from( - displayNameMapSorted.keys() - ); - }); - AppApi.GetVRChatUserModeration( - API.currentUser.id, - userId - ).then((result) => { - D.avatarModeration = result; - if (result === 4) { - D.isHideAvatar = true; - } else if (result === 5) { - D.isShowAvatar = true; - } - }); - } else { - database - .getUserStats(D.ref, inCurrentWorld) - .then((ref1) => { - if (ref1.userId === D.id) { - D.lastSeen = ref1.lastSeen; - D.joinCount = ref1.joinCount; - D.timeSpent = ref1.timeSpent; - } - }); - } - groupRequest - .getRepresentedGroup({ userId }) - .then((args1) => { - D.representedGroup = args1.json; - D.representedGroup.$thumbnailUrl = - convertFileUrlToImageUrl( - args1.json.iconUrl - ); - if (!args1.json || !args1.json.isRepresenting) { - D.isRepresentedGroupLoading = false; - } - }); - D.loading = false; - }); - } - }); - this.showUserDialogHistory.delete(userId); - this.showUserDialogHistory.add(userId); - this.quickSearchItems = this.quickSearchUserHistory(); - }; - - $app.methods.applyUserDialogLocation = function (updateInstanceOccupants) { - var D = this.userDialog; - if (!D.visible) { - return; - } - var L = parseLocation(D.ref.$location.tag); - if (updateInstanceOccupants && L.isRealInstance) { - instanceRequest.getInstance({ - worldId: L.worldId, - instanceId: L.instanceId - }); - } - D.$location = L; - if (L.userId) { - var ref = API.cachedUsers.get(L.userId); - if (typeof ref === 'undefined') { - userRequest - .getUser({ - userId: L.userId - }) - .then((args) => { - Vue.set(L, 'user', args.ref); - return args; - }); - } else { - L.user = ref; - } - } - var users = []; - var friendCount = 0; - var playersInInstance = this.lastLocation.playerList; - var cachedCurrentUser = API.cachedUsers.get(API.currentUser.id); - var currentLocation = cachedCurrentUser.$location.tag; - if (!L.isOffline && currentLocation === L.tag) { - var ref = API.cachedUsers.get(API.currentUser.id); - if (typeof ref !== 'undefined') { - users.push(ref); // add self - } - } - // dont use gamelog when using api location - if ( - this.lastLocation.location === L.tag && - playersInInstance.size > 0 - ) { - var friendsInInstance = this.lastLocation.friendList; - for (var friend of friendsInInstance.values()) { - // if friend isn't in instance add them - var addUser = !users.some(function (user) { - return friend.userId === user.id; - }); - if (addUser) { - var ref = API.cachedUsers.get(friend.userId); - if (typeof ref !== 'undefined') { - users.push(ref); - } - } - } - friendCount = users.length - 1; - } - if (!L.isOffline) { - for (var friend of this.friends.values()) { - if (typeof friend.ref === 'undefined') { - continue; - } - if (friend.ref.location === this.lastLocation.location) { - // don't add friends to currentUser gameLog instance (except when traveling) - continue; - } - if (friend.ref.$location.tag === L.tag) { - if ( - friend.state !== 'online' && - friend.ref.location === 'private' - ) { - // don't add offline friends to private instances - continue; - } - // if friend isn't in instance add them - var addUser = !users.some(function (user) { - return friend.name === user.displayName; - }); - if (addUser) { - users.push(friend.ref); - } - } - } - friendCount = users.length; - } - if (this.instanceUsersSortAlphabetical) { - users.sort(compareByDisplayName); - } else { - users.sort(compareByLocationAt); - } - D.users = users; - if ( - L.worldId && - currentLocation === L.tag && - playersInInstance.size > 0 - ) { - D.instance = { - id: L.instanceId, - tag: L.tag, - $location: L, - friendCount: 0, - users: [], - shortName: '', - ref: {} - }; - } - if (!L.isRealInstance) { - D.instance = { - id: L.instanceId, - tag: L.tag, - $location: L, - friendCount: 0, - users: [], - shortName: '', - ref: {} - }; - } - var instanceRef = API.cachedInstances.get(L.tag); - if (typeof instanceRef !== 'undefined') { - D.instance.ref = instanceRef; - } - D.instance.friendCount = friendCount; - this.updateTimers(); - }; - - // #endregion - // #region | App: player list - - API.$on('LOGIN', function () { - $app.currentInstanceUserList.data = []; - }); - - API.$on('USER:APPLY', function (ref) { - // add user ref to playerList, friendList, photonLobby, photonLobbyCurrent - var playerListRef = $app.lastLocation.playerList.get(ref.id); - if (playerListRef) { - // add/remove friends from lastLocation.friendList - if ( - !$app.lastLocation.friendList.has(ref.id) && - $app.friends.has(ref.id) - ) { - var userMap = { - displayName: ref.displayName, - userId: ref.id, - joinTime: playerListRef.joinTime - }; - $app.lastLocation.friendList.set(ref.id, userMap); - } - if ( - $app.lastLocation.friendList.has(ref.id) && - !$app.friends.has(ref.id) - ) { - $app.lastLocation.friendList.delete(ref.id); - } - $app.photonLobby.forEach((ref1, id) => { - if ( - typeof ref1 !== 'undefined' && - ref1.displayName === ref.displayName && - ref1 !== ref - ) { - $app.photonLobby.set(id, ref); - if ($app.photonLobbyCurrent.has(id)) { - $app.photonLobbyCurrent.set(id, ref); - } - } - }); - $app.getCurrentInstanceUserList(); - } - }); - - $app.data.updatePlayerListTimer = null; - $app.data.updatePlayerListPending = false; - $app.methods.getCurrentInstanceUserList = function () { - if (!this.friendLogInitStatus) { - return; - } - if (this.updatePlayerListTimer) { - this.updatePlayerListPending = true; - } else { - this.updatePlayerListExecute(); - this.updatePlayerListTimer = setTimeout(() => { - if (this.updatePlayerListPending) { - this.updatePlayerListExecute(); - } - this.updatePlayerListTimer = null; - }, 150); - } - }; - - $app.methods.updatePlayerListExecute = function () { - try { - this.updatePlayerListDebounce(); - } catch (err) { - console.error(err); - } - this.updatePlayerListTimer = null; - this.updatePlayerListPending = false; - }; - - $app.methods.updatePlayerListDebounce = function () { - var users = []; - var pushUser = function (ref) { - var photonId = ''; - var isFriend = false; - $app.photonLobbyCurrent.forEach((ref1, id) => { - if (typeof ref1 !== 'undefined') { - if ( - (typeof ref.id !== 'undefined' && - typeof ref1.id !== 'undefined' && - ref1.id === ref.id) || - (typeof ref.displayName !== 'undefined' && - typeof ref1.displayName !== 'undefined' && - ref1.displayName === ref.displayName) - ) { - photonId = id; - } - } - }); - var isMaster = false; - if ( - $app.photonLobbyMaster !== 0 && - photonId === $app.photonLobbyMaster - ) { - isMaster = true; - } - var isModerator = false; - var lobbyJointime = $app.photonLobbyJointime.get(photonId); - var inVRMode = null; - var groupOnNameplate = ''; - if (typeof lobbyJointime !== 'undefined') { - inVRMode = lobbyJointime.inVRMode; - groupOnNameplate = lobbyJointime.groupOnNameplate; - isModerator = lobbyJointime.canModerateInstance; - } - // if (groupOnNameplate) { - // API.getCachedGroup({ - // groupId: groupOnNameplate - // }).then((args) => { - // groupOnNameplate = args.ref.name; - // }); - // } - var timeoutTime = 0; - if (typeof ref.id !== 'undefined') { - isFriend = ref.isFriend; - if ( - $app.timeoutHudOverlayFilter === 'VIP' || - $app.timeoutHudOverlayFilter === 'Friends' - ) { - $app.photonLobbyTimeout.forEach((ref1) => { - if (ref1.userId === ref.id) { - timeoutTime = ref1.time; - } - }); - } else { - $app.photonLobbyTimeout.forEach((ref1) => { - if (ref1.displayName === ref.displayName) { - timeoutTime = ref1.time; - } - }); - } - } - users.push({ - ref, - displayName: ref.displayName, - timer: ref.$location_at, - $trustSortNum: ref.$trustSortNum ?? 0, - photonId, - isMaster, - isModerator, - inVRMode, - groupOnNameplate, - isFriend, - timeoutTime - }); - // get block, mute - }; - - var playersInInstance = this.lastLocation.playerList; - if (playersInInstance.size > 0) { - var ref = API.cachedUsers.get(API.currentUser.id); - if (typeof ref !== 'undefined' && playersInInstance.has(ref.id)) { - pushUser(ref); - } - for (var player of playersInInstance.values()) { - // if friend isn't in instance add them - if (player.displayName === API.currentUser.displayName) { - continue; - } - var addUser = !users.some(function (user) { - return player.displayName === user.displayName; - }); - if (addUser) { - var ref = API.cachedUsers.get(player.userId); - if (typeof ref !== 'undefined') { - pushUser(ref); - } else { - var { joinTime } = this.lastLocation.playerList.get( - player.userId - ); - if (!joinTime) { - joinTime = Date.now(); - } - var ref = { - // if userId is missing just push displayName - displayName: player.displayName, - $location_at: joinTime, - $online_for: joinTime - }; - pushUser(ref); - } - } - } - } - this.currentInstanceUserList.data = users; - this.updateTimers(); - }; - - $app.data.updateInstanceInfo = 0; - - $app.data.currentInstanceWorld = { - ref: {}, - instance: {}, - isPC: false, - isQuest: false, - isIos: false, - avatarScalingDisabled: false, - focusViewDisabled: false, - inCache: false, - cacheSize: '', - bundleSizes: [], - lastUpdated: '' - }; - - $app.data.currentInstanceWorldDescriptionExpanded = false; - $app.data.currentInstanceLocation = {}; - - $app.methods.updateCurrentInstanceWorld = function () { - var instanceId = this.lastLocation.location; - if (this.lastLocation.location === 'traveling') { - instanceId = this.lastLocationDestination; - } - if (!instanceId) { - this.currentInstanceWorld = { - ref: {}, - instance: {}, - isPC: false, - isQuest: false, - isIos: false, - avatarScalingDisabled: false, - focusViewDisabled: false, - inCache: false, - cacheSize: '', - bundleSizes: [], - lastUpdated: '' - }; - this.currentInstanceLocation = {}; - } else if (instanceId !== this.currentInstanceLocation.tag) { - this.currentInstanceWorld = { - ref: {}, - instance: {}, - isPC: false, - isQuest: false, - isIos: false, - avatarScalingDisabled: false, - focusViewDisabled: false, - inCache: false, - cacheSize: '', - bundleSizes: [], - lastUpdated: '' - }; - var L = parseLocation(instanceId); - this.currentInstanceLocation = L; - worldRequest - .getWorld({ - worldId: L.worldId - }) - .then((args) => { - this.currentInstanceWorld.ref = args.ref; - var { isPC, isQuest, isIos } = getAvailablePlatforms( - args.ref.unityPackages - ); - this.currentInstanceWorld.isPC = isPC; - this.currentInstanceWorld.isQuest = isQuest; - this.currentInstanceWorld.isIos = isIos; - this.currentInstanceWorld.avatarScalingDisabled = - args.ref?.tags.includes( - 'feature_avatar_scaling_disabled' - ); - this.currentInstanceWorld.focusViewDisabled = - args.ref?.tags.includes('feature_focus_view_disabled'); - checkVRChatCache(args.ref).then((cacheInfo) => { - if (cacheInfo.Item1 > 0) { - this.currentInstanceWorld.inCache = true; - this.currentInstanceWorld.cacheSize = `${( - cacheInfo.Item1 / 1048576 - ).toFixed(2)} MB`; - } - }); - this.getBundleDateSize(args.ref).then((bundleSizes) => { - this.currentInstanceWorld.bundleSizes = bundleSizes; - }); - return args; - }); - } else { - worldRequest - .getCachedWorld({ - worldId: this.currentInstanceLocation.worldId - }) - .then((args) => { - this.currentInstanceWorld.ref = args.ref; - var { isPC, isQuest, isIos } = getAvailablePlatforms( - args.ref.unityPackages - ); - this.currentInstanceWorld.isPC = isPC; - this.currentInstanceWorld.isQuest = isQuest; - this.currentInstanceWorld.isIos = isIos; - checkVRChatCache(args.ref).then((cacheInfo) => { - if (cacheInfo.Item1 > 0) { - this.currentInstanceWorld.inCache = true; - this.currentInstanceWorld.cacheSize = `${( - cacheInfo.Item1 / 1048576 - ).toFixed(2)} MB`; - } - }); - }); - } - if (isRealInstance(instanceId)) { - var ref = API.cachedInstances.get(instanceId); - if (typeof ref !== 'undefined') { - this.currentInstanceWorld.instance = ref; - } else { - var L = parseLocation(instanceId); - if (L.isRealInstance) { - instanceRequest - .getInstance({ - worldId: L.worldId, - instanceId: L.instanceId - }) - .then((args) => { - this.currentInstanceWorld.instance = args.ref; - }); - } - } - } - }; - - $app.methods.updateTimers = function () { - for (var $timer of $timers) { - $timer.update(); - } - }; - - $app.methods.lookupAvatars = async function (type, search) { - var avatars = new Map(); - if (type === 'search') { - try { - var response = await webApiService.execute({ - url: `${ - this.avatarRemoteDatabaseProvider - }?${type}=${encodeURIComponent(search)}&n=5000`, - method: 'GET', - headers: { - Referer: 'https://vrcx.app', - 'VRCX-ID': this.vrcxId - } - }); - var json = JSON.parse(response.data); - if (this.debugWebRequests) { - console.log(json, response); - } - if (response.status === 200 && typeof json === 'object') { - json.forEach((avatar) => { - if (!avatars.has(avatar.Id)) { - var ref = { - authorId: '', - authorName: '', - name: '', - description: '', - id: '', - imageUrl: '', - thumbnailImageUrl: '', - created_at: '0001-01-01T00:00:00.0000000Z', - updated_at: '0001-01-01T00:00:00.0000000Z', - releaseStatus: 'public', - ...avatar - }; - avatars.set(ref.id, ref); - } - }); - } else { - throw new Error(`Error: ${response.data}`); - } - } catch (err) { - var msg = `Avatar search failed for ${search} with ${this.avatarRemoteDatabaseProvider}\n${err}`; - console.error(msg); - this.$message({ - message: msg, - type: 'error' - }); - } - } else if (type === 'authorId') { - var length = this.avatarRemoteDatabaseProviderList.length; - for (var i = 0; i < length; ++i) { - var url = this.avatarRemoteDatabaseProviderList[i]; - var avatarArray = await this.lookupAvatarsByAuthor(url, search); - avatarArray.forEach((avatar) => { - if (!avatars.has(avatar.id)) { - avatars.set(avatar.id, avatar); - } - }); - } - } - return avatars; - }; - - $app.methods.lookupAvatarByImageFileId = async function (authorId, fileId) { - var length = this.avatarRemoteDatabaseProviderList.length; - for (var i = 0; i < length; ++i) { - var url = this.avatarRemoteDatabaseProviderList[i]; - var avatarArray = await this.lookupAvatarsByAuthor(url, authorId); - for (var avatar of avatarArray) { - if (extractFileId(avatar.imageUrl) === fileId) { - return avatar.id; - } - } - } - return null; - }; - - $app.methods.lookupAvatarsByAuthor = async function (url, authorId) { - var avatars = []; - if (!url) { - return avatars; - } - try { - var response = await webApiService.execute({ - url: `${url}?authorId=${encodeURIComponent(authorId)}`, - method: 'GET', - headers: { - Referer: 'https://vrcx.app', - 'VRCX-ID': this.vrcxId - } - }); - var json = JSON.parse(response.data); - if (this.debugWebRequests) { - console.log(json, response); - } - if (response.status === 200 && typeof json === 'object') { - json.forEach((avatar) => { - var ref = { - authorId: '', - authorName: '', - name: '', - description: '', - id: '', - imageUrl: '', - thumbnailImageUrl: '', - created_at: '0001-01-01T00:00:00.0000000Z', - updated_at: '0001-01-01T00:00:00.0000000Z', - releaseStatus: 'public', - ...avatar - }; - avatars.push(ref); - }); - } else { - throw new Error(`Error: ${response.data}`); - } - } catch (err) { - var msg = `Avatar lookup failed for ${authorId} with ${url}\n${err}`; - console.error(msg); - this.$message({ - message: msg, - type: 'error' - }); - } - return avatars; - }; - - $app.methods.sortUserDialogAvatars = function (array) { - var D = this.userDialog; - if (D.avatarSorting === 'update') { - array.sort($utils.compareByUpdatedAt); - } else { - array.sort($utils.compareByName); - } - D.avatars = array; - }; - - $app.methods.refreshUserDialogAvatars = function (fileId) { - var D = this.userDialog; - if (D.isAvatarsLoading) { - return; - } - D.isAvatarsLoading = true; - if (fileId) { - D.loading = true; - } - D.avatarSorting = 'update'; - D.avatarReleaseStatus = 'all'; - var params = { - n: 50, - offset: 0, - sort: 'updated', - order: 'descending', - releaseStatus: 'all', - user: 'me' - }; - for (let ref of API.cachedAvatars.values()) { - if (ref.authorId === D.id) { - API.cachedAvatars.delete(ref.id); - } - } - var map = new Map(); - API.bulk({ - fn: avatarRequest.getAvatars, - N: -1, - params, - handle: (args) => { - for (var json of args.json) { - var $ref = API.cachedAvatars.get(json.id); - if (typeof $ref !== 'undefined') { - map.set($ref.id, $ref); - } - } - }, - done: () => { - var array = Array.from(map.values()); - this.sortUserDialogAvatars(array); - D.isAvatarsLoading = false; - if (fileId) { - D.loading = false; - for (let ref of array) { - if (extractFileId(ref.imageUrl) === fileId) { - this.showAvatarDialog(ref.id); - return; - } - } - this.$message({ - message: 'Own avatar not found', - type: 'error' - }); - } - } - }); - }; - - $app.methods.refreshUserDialogTreeData = function () { - var D = this.userDialog; - if (D.id === API.currentUser.id) { - var treeData = { - ...API.currentUser, - ...D.ref - }; - D.treeData = $utils.buildTreeData(treeData); - return; - } - D.treeData = $utils.buildTreeData(D.ref); - }; - - // #endregion - // #region | App: World Dialog - - $app.data.worldDialog = { - visible: false, - loading: false, - id: '', - memo: '', - $location: {}, - ref: {}, - isFavorite: false, - avatarScalingDisabled: false, - focusViewDisabled: false, - rooms: [], - treeData: [], - bundleSizes: [], - lastUpdated: '', - inCache: false, - cacheSize: 0, - cacheLocked: false, - cachePath: '', - lastVisit: '', - visitCount: 0, - timeSpent: 0, - isPC: false, - isQuest: false, - isIos: false, - hasPersistData: false - }; - - API.$on('LOGOUT', function () { - $app.worldDialog.visible = false; - }); - - API.$on('WORLD', function (args) { - var { ref } = args; - var D = $app.worldDialog; - if (D.visible === false || D.id !== ref.id) { - return; - } - D.ref = ref; - D.avatarScalingDisabled = ref.tags?.includes( - 'feature_avatar_scaling_disabled' - ); - D.focusViewDisabled = ref.tags?.includes('feature_focus_view_disabled'); - $app.applyWorldDialogInstances(); - for (var room of D.rooms) { - if (isRealInstance(room.tag)) { - instanceRequest.getInstance({ - worldId: D.id, - instanceId: room.id - }); - } - } - if (D.bundleSizes.length === 0) { - $app.getBundleDateSize(ref).then((bundleSizes) => { - D.bundleSizes = bundleSizes; - }); - } - }); - - $app.methods.getBundleDateSize = async function (ref) { - var bundleSizes = []; - for (let i = ref.unityPackages.length - 1; i > -1; i--) { - var unityPackage = ref.unityPackages[i]; - if ( - unityPackage.variant && - unityPackage.variant !== 'standard' && - unityPackage.variant !== 'security' - ) { - continue; - } - if (!compareUnityVersion(unityPackage.unitySortNumber)) { - continue; - } - - var platform = unityPackage.platform; - if (bundleSizes[platform]) { - continue; - } - var assetUrl = unityPackage.assetUrl; - var fileId = extractFileId(assetUrl); - var fileVersion = parseInt(extractFileVersion(assetUrl), 10); - if (!fileId) { - continue; - } - var args = await miscRequest.getBundles(fileId); - if (!args?.json?.versions) { - continue; - } - - var { versions } = args.json; - for (let j = versions.length - 1; j > -1; j--) { - var version = versions[j]; - if (version.version === fileVersion) { - var createdAt = version.created_at; - var fileSize = `${( - version.file.sizeInBytes / 1048576 - ).toFixed(2)} MB`; - bundleSizes[platform] = { - createdAt, - fileSize - }; - - // update avatar dialog - if (this.avatarDialog.id === ref.id) { - this.avatarDialog.bundleSizes[platform] = - bundleSizes[platform]; - if ( - this.avatarDialog.lastUpdated < version.created_at - ) { - this.avatarDialog.lastUpdated = version.created_at; - } - } - // update world dialog - if (this.worldDialog.id === ref.id) { - this.worldDialog.bundleSizes[platform] = - bundleSizes[platform]; - if (this.worldDialog.lastUpdated < version.created_at) { - this.worldDialog.lastUpdated = version.created_at; - } - } - // update player list - if (this.currentInstanceLocation.worldId === ref.id) { - this.currentInstanceWorld.bundleSizes[platform] = - bundleSizes[platform]; - - if ( - this.currentInstanceWorld.lastUpdated < - version.created_at - ) { - this.currentInstanceWorld.lastUpdated = - version.created_at; - } - } - break; - } - } - } - - return bundleSizes; - }; - - API.$on('FAVORITE', function (args) { - var { ref } = args; - var D = $app.worldDialog; - if (D.visible === false || ref.$isDeleted || ref.favoriteId !== D.id) { - return; - } - D.isFavorite = true; - }); - - API.$on('FAVORITE:@DELETE', function (args) { - var D = $app.worldDialog; - if (D.visible === false || D.id !== args.ref.favoriteId) { - return; - } - D.isFavorite = $app.localWorldFavoritesList.includes(D.id); - }); - - $app.methods.showWorldDialog = function (tag, shortName) { - const D = this.worldDialog; - const L = parseLocation(tag); - if (L.worldId === '') { - return; - } - L.shortName = shortName; - D.id = L.worldId; - D.$location = L; - D.treeData = []; - D.bundleSizes = []; - D.lastUpdated = ''; - D.visible = true; - D.loading = true; - D.inCache = false; - D.cacheSize = 0; - D.cacheLocked = false; - D.rooms = []; - D.lastVisit = ''; - D.visitCount = ''; - D.timeSpent = 0; - D.isFavorite = false; - D.avatarScalingDisabled = false; - D.focusViewDisabled = false; - D.isPC = false; - D.isQuest = false; - D.isIos = false; - D.hasPersistData = false; - D.memo = ''; - var LL = parseLocation(this.lastLocation.location); - var currentWorldMatch = false; - if (LL.worldId === D.id) { - currentWorldMatch = true; - } - this.getWorldMemo(D.id).then((memo) => { - if (memo.worldId === D.id) { - D.memo = memo.memo; - } - }); - database.getLastVisit(D.id, currentWorldMatch).then((ref) => { - if (ref.worldId === D.id) { - D.lastVisit = ref.created_at; - } - }); - database.getVisitCount(D.id).then((ref) => { - if (ref.worldId === D.id) { - D.visitCount = ref.visitCount; - } - }); - database.getTimeSpentInWorld(D.id).then((ref) => { - if (ref.worldId === D.id) { - D.timeSpent = ref.timeSpent; - } - }); - worldRequest - .getCachedWorld({ - worldId: L.worldId - }) - .catch((err) => { - D.loading = false; - D.visible = false; - this.$message({ - message: 'Failed to load world', - type: 'error' - }); - throw err; - }) - .then((args) => { - if (D.id === args.ref.id) { - D.loading = false; - D.ref = args.ref; - D.isFavorite = API.cachedFavoritesByObjectId.has(D.id); - if (!D.isFavorite) { - D.isFavorite = this.localWorldFavoritesList.includes( - D.id - ); - } - var { isPC, isQuest, isIos } = getAvailablePlatforms( - args.ref.unityPackages - ); - D.avatarScalingDisabled = args.ref?.tags.includes( - 'feature_avatar_scaling_disabled' - ); - D.focusViewDisabled = args.ref?.tags.includes( - 'feature_focus_view_disabled' - ); - D.isPC = isPC; - D.isQuest = isQuest; - D.isIos = isIos; - this.updateVRChatWorldCache(); - miscRequest.hasWorldPersistData({ worldId: D.id }); - if (args.cache) { - worldRequest - .getWorld(args.params) - .catch((err) => { - throw err; - }) - .then((args1) => { - if (D.id === args1.ref.id) { - D.ref = args1.ref; - this.updateVRChatWorldCache(); - } - return args1; - }); - } - } - return args; - }); - }; - - $app.methods.applyWorldDialogInstances = function () { - var D = this.worldDialog; - if (!D.visible) { - return; - } - var instances = {}; - if (D.ref.instances) { - for (var instance of D.ref.instances) { - // instance = [ instanceId, occupants ] - var instanceId = instance[0]; - instances[instanceId] = { - id: instanceId, - tag: `${D.id}:${instanceId}`, - $location: {}, - friendCount: 0, - users: [], - shortName: '', - ref: {} - }; - } - } - var { instanceId, shortName } = D.$location; - if (instanceId && typeof instances[instanceId] === 'undefined') { - instances[instanceId] = { - id: instanceId, - tag: `${D.id}:${instanceId}`, - $location: {}, - friendCount: 0, - users: [], - shortName, - ref: {} - }; - } - var cachedCurrentUser = API.cachedUsers.get(API.currentUser.id); - var lastLocation$ = cachedCurrentUser.$location; - var playersInInstance = this.lastLocation.playerList; - if (lastLocation$.worldId === D.id && playersInInstance.size > 0) { - // pull instance json from cache - var friendsInInstance = this.lastLocation.friendList; - var instance = { - id: lastLocation$.instanceId, - tag: lastLocation$.tag, - $location: {}, - friendCount: friendsInInstance.size, - users: [], - shortName: '', - ref: {} - }; - instances[instance.id] = instance; - for (var friend of friendsInInstance.values()) { - // if friend isn't in instance add them - var addUser = !instance.users.some(function (user) { - return friend.userId === user.id; - }); - if (addUser) { - var ref = API.cachedUsers.get(friend.userId); - if (typeof ref !== 'undefined') { - instance.users.push(ref); - } - } - } - } - for (var { ref } of this.friends.values()) { - if ( - typeof ref === 'undefined' || - typeof ref.$location === 'undefined' || - ref.$location.worldId !== D.id || - (ref.$location.instanceId === lastLocation$.instanceId && - playersInInstance.size > 0 && - ref.location !== 'traveling') - ) { - continue; - } - if (ref.location === this.lastLocation.location) { - // don't add friends to currentUser gameLog instance (except when traveling) - continue; - } - var { instanceId } = ref.$location; - var instance = instances[instanceId]; - if (typeof instance === 'undefined') { - instance = { - id: instanceId, - tag: `${D.id}:${instanceId}`, - $location: {}, - friendCount: 0, - users: [], - shortName: '', - ref: {} - }; - instances[instanceId] = instance; - } - instance.users.push(ref); - } - var ref = API.cachedUsers.get(API.currentUser.id); - if (typeof ref !== 'undefined' && ref.$location.worldId === D.id) { - var { instanceId } = ref.$location; - var instance = instances[instanceId]; - if (typeof instance === 'undefined') { - instance = { - id: instanceId, - tag: `${D.id}:${instanceId}`, - $location: {}, - friendCount: 0, - users: [], - shortName: '', - ref: {} - }; - instances[instanceId] = instance; - } - instance.users.push(ref); // add self - } - var rooms = []; - for (var instance of Object.values(instances)) { - // due to references on callback of API.getUser() - // this should be block scope variable - const L = parseLocation(`${D.id}:${instance.id}`); - instance.location = L.tag; - if (!L.shortName) { - L.shortName = instance.shortName; - } - instance.$location = L; - if (L.userId) { - var ref = API.cachedUsers.get(L.userId); - if (typeof ref === 'undefined') { - userRequest - .getUser({ - userId: L.userId - }) - .then((args) => { - Vue.set(L, 'user', args.ref); - return args; - }); - } else { - L.user = ref; - } - } - if (instance.friendCount === 0) { - instance.friendCount = instance.users.length; - } - if (this.instanceUsersSortAlphabetical) { - instance.users.sort(compareByDisplayName); - } else { - instance.users.sort(compareByLocationAt); - } - rooms.push(instance); - } - // get instance from cache - for (var room of rooms) { - var ref = API.cachedInstances.get(room.tag); - if (typeof ref !== 'undefined') { - room.ref = ref; - } - } - rooms.sort(function (a, b) { - // sort selected and current instance to top - if ( - b.location === D.$location.tag || - b.location === lastLocation$.tag - ) { - // sort selected instance above current instance - if (a.location === D.$location.tag) { - return -1; - } - return 1; - } - if ( - a.location === D.$location.tag || - a.location === lastLocation$.tag - ) { - // sort selected instance above current instance - if (b.location === D.$location.tag) { - return 1; - } - return -1; - } - // sort by number of users when no friends in instance - if (a.users.length === 0 && b.users.length === 0) { - if (a.ref?.userCount < b.ref?.userCount) { - return 1; - } - return -1; - } - // sort by number of friends in instance - if (a.users.length < b.users.length) { - return 1; - } - return -1; - }); - D.rooms = rooms; - this.updateTimers(); - }; - - $app.methods.applyGroupDialogInstances = function (inputInstances) { - var D = this.groupDialog; - if (!D.visible) { - return; - } - var instances = {}; - for (var instance of D.instances) { - instances[instance.tag] = { - ...instance, - friendCount: 0, - users: [] - }; - } - if (typeof inputInstances !== 'undefined') { - for (var instance of inputInstances) { - instances[instance.location] = { - id: instance.instanceId, - tag: instance.location, - $location: {}, - friendCount: 0, - users: [], - shortName: instance.shortName, - ref: instance - }; - } - } - var cachedCurrentUser = API.cachedUsers.get(API.currentUser.id); - var lastLocation$ = cachedCurrentUser.$location; - var currentLocation = lastLocation$.tag; - var playersInInstance = this.lastLocation.playerList; - if (lastLocation$.groupId === D.id && playersInInstance.size > 0) { - var friendsInInstance = this.lastLocation.friendList; - var instance = { - id: lastLocation$.instanceId, - tag: currentLocation, - $location: {}, - friendCount: friendsInInstance.size, - users: [], - shortName: '', - ref: {} - }; - instances[currentLocation] = instance; - for (var friend of friendsInInstance.values()) { - // if friend isn't in instance add them - var addUser = !instance.users.some(function (user) { - return friend.userId === user.id; - }); - if (addUser) { - var ref = API.cachedUsers.get(friend.userId); - if (typeof ref !== 'undefined') { - instance.users.push(ref); - } - } - } - } - for (var { ref } of this.friends.values()) { - if ( - typeof ref === 'undefined' || - typeof ref.$location === 'undefined' || - ref.$location.groupId !== D.id || - (ref.$location.instanceId === lastLocation$.instanceId && - playersInInstance.size > 0 && - ref.location !== 'traveling') - ) { - continue; - } - if (ref.location === this.lastLocation.location) { - // don't add friends to currentUser gameLog instance (except when traveling) - continue; - } - var { instanceId, tag } = ref.$location; - var instance = instances[tag]; - if (typeof instance === 'undefined') { - instance = { - id: instanceId, - tag, - $location: {}, - friendCount: 0, - users: [], - shortName: '', - ref: {} - }; - instances[tag] = instance; - } - instance.users.push(ref); - } - var ref = API.cachedUsers.get(API.currentUser.id); - if (typeof ref !== 'undefined' && ref.$location.groupId === D.id) { - var { instanceId, tag } = ref.$location; - var instance = instances[tag]; - if (typeof instance === 'undefined') { - instance = { - id: instanceId, - tag, - $location: {}, - friendCount: 0, - users: [], - shortName: '', - ref: {} - }; - instances[tag] = instance; - } - instance.users.push(ref); // add self - } - var rooms = []; - for (var instance of Object.values(instances)) { - // due to references on callback of API.getUser() - // this should be block scope variable - const L = parseLocation(instance.tag); - instance.location = instance.tag; - instance.$location = L; - if (instance.friendCount === 0) { - instance.friendCount = instance.users.length; - } - if (this.instanceUsersSortAlphabetical) { - instance.users.sort(compareByDisplayName); - } else { - instance.users.sort(compareByLocationAt); - } - rooms.push(instance); - } - // get instance - for (var room of rooms) { - var ref = API.cachedInstances.get(room.tag); - if (typeof ref !== 'undefined') { - room.ref = ref; - } else if (isRealInstance(room.tag)) { - instanceRequest.getInstance({ - worldId: room.$location.worldId, - instanceId: room.$location.instanceId - }); - } - } - rooms.sort(function (a, b) { - // sort current instance to top - if (b.location === currentLocation) { - return 1; - } - if (a.location === currentLocation) { - return -1; - } - // sort by number of users when no friends in instance - if (a.users.length === 0 && b.users.length === 0) { - if (a.ref?.userCount < b.ref?.userCount) { - return 1; - } - return -1; - } - // sort by number of friends in instance - if (a.users.length < b.users.length) { - return 1; - } - return -1; - }); - D.instances = rooms; - this.updateTimers(); - }; - - $app.methods.worldDialogCommand = function (command) { - var D = this.worldDialog; - if (D.visible === false) { - return; - } - switch (command) { - case 'New Instance and Self Invite': - this.newInstanceSelfInvite(D.id); - break; - case 'Rename': - this.promptRenameWorld(D); - break; - case 'Change Description': - this.promptChangeWorldDescription(D); - break; - case 'Change Capacity': - this.promptChangeWorldCapacity(D); - break; - case 'Change Recommended Capacity': - this.promptChangeWorldRecommendedCapacity(D); - break; - case 'Change YouTube Preview': - this.promptChangeWorldYouTubePreview(D); - break; - } - }; - - $app.methods.newInstanceSelfInvite = function (worldId) { - this.createNewInstance(worldId).then((args) => { - const location = args?.json?.location; - if (!location) { - this.$message({ - message: 'Failed to create instance', - type: 'error' - }); - return; - } - // self invite - var L = parseLocation(location); - if (!L.isRealInstance) { - return; - } - instanceRequest - .selfInvite({ - instanceId: L.instanceId, - worldId: L.worldId - }) - .then((args) => { - this.$message({ - message: 'Self invite sent', - type: 'success' - }); - return args; - }); - }); - }; - - // #endregion - // #region | App: Avatar Dialog - - $app.data.avatarDialog = { - visible: false, - loading: false, - id: '', - memo: '', - ref: {}, - isFavorite: false, - isBlocked: false, - isQuestFallback: false, - hasImposter: false, - imposterVersion: '', - isPC: false, - isQuest: false, - isIos: false, - bundleSizes: [], - platformInfo: {}, - galleryImages: [], - galleryLoading: false, - lastUpdated: '', - inCache: false, - cacheSize: 0, - cacheLocked: false, - cachePath: '' - }; - - API.$on('FAVORITE', function (args) { - var { ref } = args; - var D = $app.avatarDialog; - if (D.visible === false || ref.$isDeleted || ref.favoriteId !== D.id) { - return; - } - D.isFavorite = true; - }); - - API.$on('FAVORITE:@DELETE', function (args) { - var D = $app.avatarDialog; - if (D.visible === false || D.id !== args.ref.favoriteId) { - return; - } - D.isFavorite = false; - }); - - $app.methods.showAvatarDialog = function (avatarId) { - var D = this.avatarDialog; - D.visible = true; - D.loading = true; - D.id = avatarId; - D.inCache = false; - D.cacheSize = 0; - D.cacheLocked = false; - D.cachePath = ''; - D.isQuestFallback = false; - D.isPC = false; - D.isQuest = false; - D.isIos = false; - D.hasImposter = false; - D.imposterVersion = ''; - D.lastUpdated = ''; - D.bundleSizes = []; - D.platformInfo = {}; - D.galleryImages = []; - D.galleryLoading = true; - D.isFavorite = - API.cachedFavoritesByObjectId.has(avatarId) || - (API.currentUser.$isVRCPlus && - this.localAvatarFavoritesList.includes(avatarId)); - D.isBlocked = API.cachedAvatarModerations.has(avatarId); - var ref2 = API.cachedAvatars.get(avatarId); - if (typeof ref2 !== 'undefined') { - D.ref = ref2; - this.updateVRChatAvatarCache(); - if ( - ref2.releaseStatus !== 'public' && - ref2.authorId !== API.currentUser.id - ) { - D.loading = false; - return; - } - } - avatarRequest - .getAvatar({ avatarId }) - .then((args) => { - var { ref } = args; - D.ref = ref; - this.getAvatarGallery(avatarId); - this.updateVRChatAvatarCache(); - if (/quest/.test(ref.tags)) { - D.isQuestFallback = true; - } - var { isPC, isQuest, isIos } = getAvailablePlatforms( - args.ref.unityPackages - ); - D.isPC = isPC; - D.isQuest = isQuest; - D.isIos = isIos; - D.platformInfo = getPlatformInfo(args.ref.unityPackages); - for (let i = ref.unityPackages.length - 1; i > -1; i--) { - var unityPackage = ref.unityPackages[i]; - if (unityPackage.variant === 'impostor') { - D.hasImposter = true; - D.imposterVersion = unityPackage.impostorizerVersion; - break; - } - } - if (D.bundleSizes.length === 0) { - this.getBundleDateSize(ref).then((bundleSizes) => { - D.bundleSizes = bundleSizes; - }); - } - }) - .catch((err) => { - D.visible = false; - throw err; - }) - .finally(() => { - this.$nextTick(() => (D.loading = false)); - }); - }; - - $app.methods.getAvatarGallery = async function (avatarId) { - var D = this.avatarDialog; - const args = await avatarRequest - .getAvatarGallery(avatarId) - .finally(() => { - D.galleryLoading = false; - }); - if (args.params.galleryId !== D.id) { - return; - } - D.galleryImages = []; - // wtf is this? why is order sorting only needed if it's your own avatar? - const sortedGallery = args.json.sort((a, b) => { - if (!a.order && !b.order) { - return 0; - } - return a.order - b.order; - }); - for (const file of sortedGallery) { - const url = file.versions[file.versions.length - 1].file.url; - D.galleryImages.push(url); - } - - // for JSON tab treeData - D.ref.gallery = args.json; - return D.galleryImages; - }; - - $app.methods.selectAvatarWithConfirmation = function (id) { - this.$confirm(`Continue? Select Avatar`, 'Confirm', { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - callback: (action) => { - if (action !== 'confirm') { - return; - } - $app.selectAvatarWithoutConfirmation(id); - } - }); - }; - - $app.methods.selectAvatarWithoutConfirmation = function (id) { - if (API.currentUser.currentAvatar === id) { - this.$message({ - message: 'Avatar already selected', - type: 'info' - }); - return; - } - avatarRequest - .selectAvatar({ - avatarId: id - }) - .then((args) => { - new Noty({ - type: 'success', - text: 'Avatar changed via launch command' - }).show(); - return args; - }); - }; - - $app.methods.checkAvatarCache = function (fileId) { - var avatarId = ''; - for (var ref of API.cachedAvatars.values()) { - if (extractFileId(ref.imageUrl) === fileId) { - avatarId = ref.id; - } - } - return avatarId; - }; - - $app.methods.checkAvatarCacheRemote = async function (fileId, ownerUserId) { - if (this.avatarRemoteDatabase) { - var avatarId = await this.lookupAvatarByImageFileId( - ownerUserId, - fileId - ); - return avatarId; - } - return null; - }; - - $app.methods.showAvatarAuthorDialog = async function ( - refUserId, - ownerUserId, - currentAvatarImageUrl - ) { - var fileId = extractFileId(currentAvatarImageUrl); - if (!fileId) { - this.$message({ - message: 'Sorry, the author is unknown', - type: 'error' - }); - } else if (refUserId === API.currentUser.id) { - this.showAvatarDialog(API.currentUser.currentAvatar); - } else { - var avatarId = await this.checkAvatarCache(fileId); - if (!avatarId) { - var avatarInfo = await this.getAvatarName( - currentAvatarImageUrl - ); - if (avatarInfo.ownerId === API.currentUser.id) { - this.refreshUserDialogAvatars(fileId); - } - } - if (!avatarId) { - avatarId = await this.checkAvatarCacheRemote( - fileId, - avatarInfo.ownerId - ); - } - if (!avatarId) { - if (avatarInfo.ownerId === refUserId) { - this.$message({ - message: - "It's personal (own) avatar or not found in avatar database", - type: 'warning' - }); - } else { - this.$message({ - message: 'Avatar not found in avatar database', - type: 'warning' - }); - this.showUserDialog(avatarInfo.ownerId); - } - } - if (avatarId) { - this.showAvatarDialog(avatarId); - } - } - }; - - // #endregion - // #region | App: Favorite Dialog - - $app.data.favoriteDialog = { - visible: false, - loading: false, - type: '', - objectId: '', - currentGroup: {} - }; - - $app.methods.showFavoriteDialog = function (type, objectId) { - const D = this.favoriteDialog; - D.type = type; - D.objectId = objectId; - D.visible = true; - this.updateFavoriteDialog(objectId); - }; - - $app.methods.updateFavoriteDialog = function (objectId) { - var D = this.favoriteDialog; - if (!D.visible || D.objectId !== objectId) { - return; - } - D.currentGroup = {}; - var favorite = this.favoriteObjects.get(objectId); - if (favorite) { - for (var group of API.favoriteWorldGroups) { - if (favorite.groupKey === group.key) { - D.currentGroup = group; - return; - } - } - for (var group of API.favoriteAvatarGroups) { - if (favorite.groupKey === group.key) { - D.currentGroup = group; - return; - } - } - for (var group of API.favoriteFriendGroups) { - if (favorite.groupKey === group.key) { - D.currentGroup = group; - return; - } - } - } - }; - - API.$on('FAVORITE:ADD', function (args) { - $app.updateFavoriteDialog(args.params.favoriteId); - }); - - API.$on('FAVORITE:DELETE', function (args) { - $app.updateFavoriteDialog(args.params.objectId); - }); - - // #endregion - // #region | App: New Instance Dialog - - $app.data.instanceContentSettings = [ - 'emoji', - 'stickers', - 'pedestals', - 'prints', - 'drones', - 'props' - ]; - - $app.methods.createNewInstance = async function (worldId = '', options) { - let D = options; - - if (!D) { - D = { - loading: false, - accessType: await configRepository.getString( - 'instanceDialogAccessType', - 'public' - ), - region: await configRepository.getString( - 'instanceRegion', - 'US West' - ), - worldId: worldId, - groupId: await configRepository.getString( - 'instanceDialogGroupId', - '' - ), - groupAccessType: await configRepository.getString( - 'instanceDialogGroupAccessType', - 'plus' - ), - ageGate: await configRepository.getBool( - 'instanceDialogAgeGate', - false - ), - queueEnabled: await configRepository.getBool( - 'instanceDialogQueueEnabled', - true - ), - roleIds: [], - groupRef: {} - }; - } - - var type = 'public'; - var canRequestInvite = false; - switch (D.accessType) { - case 'friends': - type = 'friends'; - break; - case 'friends+': - type = 'hidden'; - break; - case 'invite': - type = 'private'; - break; - case 'invite+': - type = 'private'; - canRequestInvite = true; - break; - case 'group': - type = 'group'; - break; - } - var region = 'us'; - if (D.region === 'US East') { - region = 'use'; - } else if (D.region === 'Europe') { - region = 'eu'; - } else if (D.region === 'Japan') { - region = 'jp'; - } - var params = { - type, - canRequestInvite, - worldId: D.worldId, - ownerId: API.currentUser.id, - region - }; - if (type === 'group') { - params.groupAccessType = D.groupAccessType; - params.ownerId = D.groupId; - params.queueEnabled = D.queueEnabled; - if (D.groupAccessType === 'members') { - params.roleIds = D.roleIds; - } - } - if ( - D.ageGate && - type === 'group' && - hasGroupPermission(D.groupRef, 'group-instance-age-gated-create') - ) { - params.ageGate = true; - } - try { - var args = await instanceRequest.createInstance(params); - return args; - } catch (err) { - console.error(err); - return null; - } - }; - - $app.methods.makeHome = function (tag) { - this.$confirm('Continue? Make Home', 'Confirm', { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - callback: (action) => { - if (action !== 'confirm') { - return; - } - userRequest - .saveCurrentUser({ - homeLocation: tag - }) - .then((args) => { - this.$message({ - message: 'Home world updated', - type: 'success' - }); - return args; - }); - } - }); - }; - - // #endregion - // #region | App: Launch Options Dialog - - $app.data.isLaunchOptionsDialogVisible = false; - - $app.methods.showLaunchOptions = function () { - this.isLaunchOptionsDialogVisible = true; - }; - - // #endregion - // #region | App: Notification position - - $app.data.isNotificationPositionDialogVisible = false; - - $app.methods.showNotificationPositionDialog = function () { - this.isNotificationPositionDialogVisible = true; - }; - - // #endregion - // #region | App: Noty feed filters - // #region | App: Wrist feed filters - - $app.data.feedFiltersDialogMode = ''; - - $app.methods.showNotyFeedFiltersDialog = function () { - this.feedFiltersDialogMode = 'noty'; - }; - $app.methods.showWristFeedFiltersDialog = function () { - this.feedFiltersDialogMode = 'wrist'; - }; - - // #endregion - // #region | App: Launch Dialog - - $app.data.launchDialogData = { - visible: false, - loading: false, - tag: '', - shortName: '' - }; - - $app.methods.showLaunchDialog = async function (tag, shortName) { - this.launchDialogData = { - visible: true, - // flag, use for trigger adjustDialogZ - loading: true, - tag, - shortName - }; - this.$nextTick(() => (this.launchDialogData.loading = false)); - }; - - $app.methods.launchGame = async function ( - location, - shortName, - desktopMode - ) { - var L = parseLocation(location); - var args = []; - if ( - shortName && - L.instanceType !== 'public' && - L.groupAccessType !== 'public' - ) { - args.push( - `vrchat://launch?ref=vrcx.app&id=${location}&shortName=${shortName}` - ); - } else { - // fetch shortName - var newShortName = ''; - var response = await instanceRequest.getInstanceShortName({ - worldId: L.worldId, - instanceId: L.instanceId - }); - if (response.json) { - if (response.json.shortName) { - newShortName = response.json.shortName; - } else { - newShortName = response.json.secureName; - } - } - if (newShortName) { - args.push( - `vrchat://launch?ref=vrcx.app&id=${location}&shortName=${newShortName}` - ); - } else { - args.push(`vrchat://launch?ref=vrcx.app&id=${location}`); - } - } - - const launchArguments = - await configRepository.getString('launchArguments'); - - const vrcLaunchPathOverride = await configRepository.getString( - 'vrcLaunchPathOverride' - ); - - if (launchArguments) { - args.push(launchArguments); - } - if (desktopMode) { - args.push('--no-vr'); - } - if (vrcLaunchPathOverride && !LINUX) { - AppApi.StartGameFromPath( - vrcLaunchPathOverride, - args.join(' ') - ).then((result) => { - if (!result) { - this.$message({ - message: - 'Failed to launch VRChat, invalid custom path set', - type: 'error' - }); - } else { - this.$message({ - message: 'VRChat launched', - type: 'success' - }); - } - }); - } else { - AppApi.StartGame(args.join(' ')).then((result) => { - if (!result) { - this.$message({ - message: - 'Failed to find VRChat, set a custom path in launch options', - type: 'error' - }); - } else { - this.$message({ - message: 'VRChat launched', - type: 'success' - }); - } - }); - } - console.log('Launch Game', args.join(' '), desktopMode); - }; - - // #endregion - // #region | App: Copy To Clipboard - - $app.methods.copyToClipboard = function (text) { - var textArea = document.createElement('textarea'); - textArea.id = 'copy_to_clipboard'; - textArea.value = text; - textArea.style.top = '0'; - textArea.style.left = '0'; - textArea.style.position = 'fixed'; - document.body.appendChild(textArea); - textArea.focus(); - textArea.select(); - document.execCommand('copy'); - document.getElementById('copy_to_clipboard').remove(); - }; - - $app.methods.copyLink = function (text) { - this.$message({ - message: 'Link copied to clipboard', - type: 'success' - }); - this.copyToClipboard(text); - }; - - // #endregion - // #region | App: VRCPlus Icons - - API.$on('LOGIN', function () { - $app.VRCPlusIconsTable = []; - }); - - $app.methods.refreshVRCPlusIconsTable = function () { - this.galleryDialogIconsLoading = true; - var params = { - n: 100, - tag: 'icon' - }; - vrcPlusIconRequest.getFileList(params).finally(() => { - this.galleryDialogIconsLoading = false; - }); - }; - - API.$on('FILES:LIST', function (args) { - if (args.params.tag === 'icon') { - $app.VRCPlusIconsTable = args.json.reverse(); - } - }); - - API.$on('VRCPLUSICON:ADD', function (args) { - if (Object.keys($app.VRCPlusIconsTable).length !== 0) { - $app.VRCPlusIconsTable.unshift(args.json); - } - }); - - $app.data.uploadImage = ''; - - $app.methods.inviteImageUpload = function (e) { - var files = e.target.files || e.dataTransfer.files; - if (!files.length) { - return; - } - if (files[0].size >= 100000000) { - // 100MB - $app.$message({ - message: $t('message.file.too_large'), - type: 'error' - }); - this.clearInviteImageUpload(); - return; - } - if (!files[0].type.match(/image.*/)) { - $app.$message({ - message: $t('message.file.not_image'), - type: 'error' - }); - this.clearInviteImageUpload(); - return; - } - var r = new FileReader(); - r.onload = function () { - $app.uploadImage = btoa(r.result); - }; - r.readAsBinaryString(files[0]); - }; - - $app.methods.clearInviteImageUpload = function () { - var buttonList = document.querySelectorAll('.inviteImageUploadButton'); - buttonList.forEach((button) => (button.value = '')); - this.uploadImage = ''; - }; - - $app.methods.userOnlineFor = function (ctx) { - if (ctx.ref.state === 'online' && ctx.ref.$online_for) { - return $utils.timeToText(Date.now() - ctx.ref.$online_for); - } else if (ctx.ref.state === 'active' && ctx.ref.$active_for) { - return $utils.timeToText(Date.now() - ctx.ref.$active_for); - } else if (ctx.ref.$offline_for) { - return $utils.timeToText(Date.now() - ctx.ref.$offline_for); - } - return '-'; - }; - - // #endregion - // #region | App: Invite Messages - - API.$on('LOGIN', function () { - $app.inviteMessageTable.data = []; - $app.inviteResponseMessageTable.data = []; - $app.inviteRequestMessageTable.data = []; - $app.inviteRequestResponseMessageTable.data = []; - $app.inviteMessageTable.visible = false; - $app.inviteResponseMessageTable.visible = false; - $app.inviteRequestMessageTable.visible = false; - $app.inviteRequestResponseMessageTable.visible = false; - }); - - // temp, invites.pug - API.refreshInviteMessageTableData = - inviteMessagesRequest.refreshInviteMessageTableData; - - API.$on('INVITE:MESSAGE', function (args) { - $app.inviteMessageTable.data = args.json; - }); - - API.$on('INVITE:RESPONSE', function (args) { - $app.inviteResponseMessageTable.data = args.json; - }); - - API.$on('INVITE:REQUEST', function (args) { - $app.inviteRequestMessageTable.data = args.json; - }); - - API.$on('INVITE:REQUESTRESPONSE', function (args) { - $app.inviteRequestResponseMessageTable.data = args.json; - }); - - // #endregion - // #region | App: Edit Invite Message Dialog - - $app.data.editInviteMessageDialog = { - visible: false, - inviteMessage: {}, - messageType: '', - newMessage: '' - }; - - $app.methods.showEditInviteMessageDialog = function ( - messageType, - inviteMessage - ) { - var D = this.editInviteMessageDialog; - D.newMessage = inviteMessage.message; - D.visible = true; - D.inviteMessage = inviteMessage; - D.messageType = messageType; - }; - - // #endregion - // #region | App: Friends List - - $app.data.friendsListSearch = ''; - // $app.data.friendsListSelectAllCheckbox = false; - - // $app.methods.showBulkUnfriendAllConfirm = function () { - // this.$confirm( - // `Are you sure you want to delete all your friends? - // This can negatively affect your trust rank, - // This action cannot be undone.`, - // 'Delete all friends?', - // { - // confirmButtonText: 'Confirm', - // cancelButtonText: 'Cancel', - // type: 'info', - // callback: (action) => { - // if (action === 'confirm') { - // this.bulkUnfriendAll(); - // } - // } - // } - // ); - // }; - - // $app.methods.bulkUnfriendAll = function () { - // for (var ctx of this.friendsListTable.data) { - // API.deleteFriend({ - // userId: ctx.id - // }); - // } - // }; - - $app.methods.getAllUserStats = async function () { - var userIds = []; - var displayNames = []; - for (var ctx of this.friends.values()) { - userIds.push(ctx.id); - if (ctx.ref?.displayName) { - displayNames.push(ctx.ref.displayName); - } - } - - var data = await database.getAllUserStats(userIds, displayNames); - var friendListMap = new Map(); - for (var item of data) { - if (!item.userId) { - // find userId from previous data with matching displayName - for (var ref of data) { - if (ref.displayName === item.displayName && ref.userId) { - item.userId = ref.userId; - } - } - // if still no userId, find userId from friends list - if (!item.userId) { - for (var ref of this.friends.values()) { - if ( - ref?.ref?.id && - ref.ref.displayName === item.displayName - ) { - item.userId = ref.id; - } - } - } - // if still no userId, skip - if (!item.userId) { - continue; - } - } - - var friend = friendListMap.get(item.userId); - if (!friend) { - friendListMap.set(item.userId, item); - continue; - } - if (Date.parse(item.lastSeen) > Date.parse(friend.lastSeen)) { - friend.lastSeen = item.lastSeen; - } - friend.timeSpent += item.timeSpent; - friend.joinCount += item.joinCount; - friend.displayName = item.displayName; - friendListMap.set(item.userId, friend); - } - for (var item of friendListMap.values()) { - var ref = this.friends.get(item.userId); - if (ref?.ref) { - ref.ref.$joinCount = item.joinCount; - ref.ref.$lastSeen = item.lastSeen; - ref.ref.$timeSpent = item.timeSpent; - } - } - }; - - $app.methods.getUserStats = async function (ctx) { - var ref = await database.getUserStats(ctx); - /* eslint-disable require-atomic-updates */ - ctx.$joinCount = ref.joinCount; - ctx.$lastSeen = ref.lastSeen; - ctx.$timeSpent = ref.timeSpent; - /* eslint-enable require-atomic-updates */ - }; - - // Set avatar/world image - - $app.methods.checkPreviousImageAvailable = async function (images) { - this.previousImagesTable = []; - for (var image of images) { - if (image.file && image.file.url) { - var response = await fetch(image.file.url, { - method: 'HEAD', - redirect: 'follow' - }).catch((error) => { - console.log(error); - }); - if (response.status === 200) { - this.previousImagesTable.push(image); - } - } - } - }; - - // todo: userdialog - $app.data.previousImagesDialogVisible = false; - $app.data.previousImagesTable = []; - - API.$on('LOGIN', function () { - $app.previousImagesTable = []; - }); - - // Avatar names - - API.cachedAvatarNames = new Map(); - - $app.methods.getAvatarName = async function (imageUrl) { - var fileId = extractFileId(imageUrl); - if (!fileId) { - return { - ownerId: '', - avatarName: '-' - }; - } - if (API.cachedAvatarNames.has(fileId)) { - return API.cachedAvatarNames.get(fileId); - } - var args = await imageRequest.getAvatarImages({ fileId }); - return storeAvatarImage(args); - }; - - // VRChat Config JSON - - $app.data.isVRChatConfigDialogVisible = false; - - $app.methods.showVRChatConfig = async function () { - this.isVRChatConfigDialogVisible = true; - if (!this.VRChatUsedCacheSize) { - this.getVRChatCacheSize(); - } - }; - - // Auto Launch Shortcuts - - $app.methods.openShortcutFolder = function () { - AppApi.OpenShortcutFolder(); - }; - - $app.methods.updateAppLauncherSettings = async function (configKey = '') { - if (configKey === 'VRCX_enableAppLauncher') { - this.enableAppLauncher = !this.enableAppLauncher; - await configRepository.setBool( - 'VRCX_enableAppLauncher', - this.enableAppLauncher - ); - } else { - this.enableAppLauncherAutoClose = !this.enableAppLauncherAutoClose; - await configRepository.setBool( - 'VRCX_enableAppLauncherAutoClose', - this.enableAppLauncherAutoClose - ); - } - - await AppApi.SetAppLauncherSettings( - this.enableAppLauncher, - this.enableAppLauncherAutoClose - ); - }; - - // Screenshot Helper - - $app.methods.saveScreenshotHelper = async function (configKey = '') { - if (configKey === 'VRCX_screenshotHelper') { - this.screenshotHelper = !this.screenshotHelper; - } else if (configKey === 'VRCX_screenshotHelperModifyFilename') { - this.screenshotHelperModifyFilename = - !this.screenshotHelperModifyFilename; - } else if (configKey === 'VRCX_screenshotHelperCopyToClipboard') { - this.screenshotHelperCopyToClipboard = - !this.screenshotHelperCopyToClipboard; - } - await configRepository.setBool( - 'VRCX_screenshotHelper', - this.screenshotHelper - ); - await configRepository.setBool( - 'VRCX_screenshotHelperModifyFilename', - this.screenshotHelperModifyFilename - ); - await configRepository.setBool( - 'VRCX_screenshotHelperCopyToClipboard', - this.screenshotHelperCopyToClipboard - ); - }; - - $app.methods.processScreenshot = async function (path) { - var newPath = path; - if (this.screenshotHelper) { - var location = parseLocation(this.lastLocation.location); - var metadata = { - application: 'VRCX', - version: 1, - author: { - id: API.currentUser.id, - displayName: API.currentUser.displayName - }, - world: { - name: this.lastLocation.name, - id: location.worldId, - instanceId: this.lastLocation.location - }, - players: [] - }; - for (var user of this.lastLocation.playerList.values()) { - metadata.players.push({ - id: user.userId, - displayName: user.displayName - }); - } - newPath = await AppApi.AddScreenshotMetadata( - path, - JSON.stringify(metadata), - location.worldId, - this.screenshotHelperModifyFilename - ); - console.log('Screenshot metadata added', newPath); - } - if (this.screenshotHelperCopyToClipboard) { - await AppApi.CopyImageToClipboard(newPath); - console.log('Screenshot copied to clipboard', newPath); - } - }; - - $app.data.screenshotMetadataDialog = { - visible: false, - loading: false, - search: '', - searchType: 'Player Name', - searchTypes: ['Player Name', 'Player ID', 'World Name', 'World ID'], - metadata: {}, - isUploading: false - }; - - $app.methods.showScreenshotMetadataDialog = function () { - this.screenshotMetadataDialog.visible = true; - }; - - $app.data.currentlyDroppingFile = null; - /** - * This function is called by .NET(CefCustomDragHandler#CefCustomDragHandler) when a file is dragged over a drop zone in the app window. - * @param {string} filePath - The full path to the file being dragged into the window - */ - $app.methods.dragEnterCef = function (filePath) { - this.currentlyDroppingFile = filePath; - }; - - // YouTube API - - $app.data.isYouTubeApiDialogVisible = false; - - $app.methods.changeYouTubeApi = async function (configKey = '') { - if (configKey === 'VRCX_youtubeAPI') { - this.youTubeApi = !this.youTubeApi; - } else if (configKey === 'VRCX_progressPie') { - this.progressPie = !this.progressPie; - } else if (configKey === 'VRCX_progressPieFilter') { - this.progressPieFilter = !this.progressPieFilter; - } - - await configRepository.setBool('VRCX_youtubeAPI', this.youTubeApi); - await configRepository.setBool('VRCX_progressPie', this.progressPie); - await configRepository.setBool( - 'VRCX_progressPieFilter', - this.progressPieFilter - ); - this.updateVRLastLocation(); - this.updateOpenVR(); - }; - - $app.methods.showYouTubeApiDialog = function () { - this.isYouTubeApiDialogVisible = true; - }; - - // Launch Command Settings handling - - $app.methods.toggleLaunchCommandSetting = async function (configKey = '') { - switch (configKey) { - case 'VRCX_showConfirmationOnSwitchAvatar': - this.showConfirmationOnSwitchAvatar = - !this.showConfirmationOnSwitchAvatar; - await configRepository.setBool( - 'VRCX_showConfirmationOnSwitchAvatar', - this.showConfirmationOnSwitchAvatar - ); - break; - default: - throw new Error( - 'toggleLaunchCommandSetting: Unknown configKey' - ); - } - }; - - // Asset Bundle Cacher - - $app.methods.updateVRChatWorldCache = function () { - var D = this.worldDialog; - if (D.visible) { - D.inCache = false; - D.cacheSize = 0; - D.cacheLocked = false; - D.cachePath = ''; - checkVRChatCache(D.ref).then((cacheInfo) => { - if (cacheInfo.Item1 > 0) { - D.inCache = true; - D.cacheSize = `${(cacheInfo.Item1 / 1048576).toFixed( - 2 - )} MB`; - D.cachePath = cacheInfo.Item3; - } - D.cacheLocked = cacheInfo.Item2; - }); - } - }; - - $app.methods.updateVRChatAvatarCache = function () { - var D = this.avatarDialog; - if (D.visible) { - D.inCache = false; - D.cacheSize = 0; - D.cacheLocked = false; - D.cachePath = ''; - checkVRChatCache(D.ref).then((cacheInfo) => { - if (cacheInfo.Item1 > 0) { - D.inCache = true; - D.cacheSize = `${(cacheInfo.Item1 / 1048576).toFixed( - 2 - )} MB`; - D.cachePath = cacheInfo.Item3; - } - D.cacheLocked = cacheInfo.Item2; - }); - } - }; - - $app.methods.getDisplayName = function (userId) { - if (userId) { - var ref = API.cachedUsers.get(userId); - if (ref.displayName) { - return ref.displayName; - } - } - return ''; - }; - - $app.methods.deleteVRChatCache = async function (ref) { - await deleteVRChatCache(ref); - this.getVRChatCacheSize(); - this.updateVRChatWorldCache(); - this.updateVRChatAvatarCache(); - }; - - $app.methods.autoVRChatCacheManagement = function () { - if (this.autoSweepVRChatCache) { - this.sweepVRChatCache(); - } - }; - - $app.methods.sweepVRChatCache = async function () { - var output = await AssetBundleManager.SweepCache(); - console.log('SweepCache', output); - if (this.isVRChatConfigDialogVisible) { - this.getVRChatCacheSize(); - } - }; - - $app.data.lastCrashedTime = null; - $app.methods.checkIfGameCrashed = function () { - if (!this.relaunchVRChatAfterCrash) { - return; - } - var { location } = this.lastLocation; - AppApi.VrcClosedGracefully().then((result) => { - if (result || !isRealInstance(location)) { - return; - } - // check if relaunched less than 2mins ago (prvent crash loop) - if ( - this.lastCrashedTime && - new Date() - this.lastCrashedTime < 120_000 - ) { - console.log('VRChat was recently crashed, not relaunching'); - return; - } - this.lastCrashedTime = new Date(); - // wait a bit for SteamVR to potentially close before deciding to relaunch - var restartDelay = 8000; - if (this.isGameNoVR) { - // wait for game to close before relaunching - restartDelay = 2000; - } - workerTimers.setTimeout( - () => this.restartCrashedGame(location), - restartDelay - ); - }); - }; - - $app.methods.restartCrashedGame = function (location) { - if (!this.isGameNoVR && !this.isSteamVRRunning) { - console.log("SteamVR isn't running, not relaunching VRChat"); - return; - } - AppApi.FocusWindow(); - var message = 'VRChat crashed, attempting to rejoin last instance'; - this.$message({ - message, - type: 'info' - }); - var entry = { - created_at: new Date().toJSON(), - type: 'Event', - data: message - }; - database.addGamelogEventToDatabase(entry); - this.queueGameLogNoty(entry); - this.addGameLog(entry); - this.launchGame(location, '', this.isGameNoVR); - }; - - $app.data.VRChatUsedCacheSize = ''; - $app.data.VRChatTotalCacheSize = ''; - $app.data.VRChatCacheSizeLoading = false; - - $app.methods.getVRChatCacheSize = async function () { - this.VRChatCacheSizeLoading = true; - var totalCacheSize = 30; - this.VRChatTotalCacheSize = totalCacheSize; - var usedCacheSize = await AssetBundleManager.GetCacheSize(); - this.VRChatUsedCacheSize = (usedCacheSize / 1073741824).toFixed(2); - this.VRChatCacheSizeLoading = false; - }; - - // Parse User URL - - $app.methods.parseUserUrl = function (user) { - var url = new URL(user); - var urlPath = url.pathname; - if (urlPath.substring(5, 11) === '/user/') { - var userId = urlPath.substring(11); - return userId; - } - return void 0; - }; - - // userDialog Groups - - $app.data.inGameGroupOrder = []; - - $app.methods.getVRChatRegistryKey = async function (key) { - if (LINUX) { - return AppApi.GetVRChatRegistryKeyString(key); - } - return AppApi.GetVRChatRegistryKey(key); - }; - - $app.methods.updateInGameGroupOrder = async function () { - this.inGameGroupOrder = []; - try { - var json = await this.getVRChatRegistryKey( - `VRC_GROUP_ORDER_${API.currentUser.id}` - ); - if (!json) { - return; - } - this.inGameGroupOrder = JSON.parse(json); - } catch (err) { - console.error(err); - } - }; - - $app.methods.sortGroupInstancesByInGame = function (a, b) { - var aIndex = this.inGameGroupOrder.indexOf(a?.group?.id); - var bIndex = this.inGameGroupOrder.indexOf(b?.group?.id); - if (aIndex === -1 && bIndex === -1) { - return 0; - } - if (aIndex === -1) { - return 1; - } - if (bIndex === -1) { - return -1; - } - return aIndex - bIndex; - }; - - // #endregion - // #region | Gallery - - $app.data.galleryDialog = {}; - $app.data.galleryDialogVisible = false; - $app.data.galleryDialogGalleryLoading = false; - $app.data.galleryDialogIconsLoading = false; - $app.data.galleryDialogEmojisLoading = false; - $app.data.galleryDialogStickersLoading = false; - $app.data.galleryDialogPrintsLoading = false; - $app.data.galleryDialogInventoryLoading = false; - - API.$on('LOGIN', function () { - $app.galleryTable = []; - }); - - $app.methods.closeGalleryDialog = function () { - this.galleryDialogVisible = false; - }; - - $app.methods.showGalleryDialog = function (pageNum) { - this.galleryDialogVisible = true; - this.refreshGalleryTable(); - this.refreshVRCPlusIconsTable(); - this.refreshEmojiTable(); - this.refreshStickerTable(); - this.refreshPrintTable(); - this.getInventory(); - workerTimers.setTimeout(() => this.setGalleryTab(pageNum), 100); - }; - - $app.methods.setGalleryTab = function (pageNum) { - if ( - typeof pageNum !== 'undefined' && - typeof this.$refs.galleryTabs !== 'undefined' - ) { - this.$refs.galleryTabs.setCurrentName(`${pageNum}`); - } - }; - - $app.methods.refreshGalleryTable = function () { - this.galleryDialogGalleryLoading = true; - var params = { - n: 100, - tag: 'gallery' - }; - vrcPlusIconRequest.getFileList(params).finally(() => { - this.galleryDialogGalleryLoading = false; - }); - }; - - API.$on('FILES:LIST', function (args) { - if (args.params.tag === 'gallery') { - $app.galleryTable = args.json.reverse(); - } - }); - - API.$on('GALLERYIMAGE:ADD', function (args) { - if (Object.keys($app.galleryTable).length !== 0) { - $app.galleryTable.unshift(args.json); - } - }); - - // #endregion - // #region | Sticker - API.$on('LOGIN', function () { - $app.stickerTable = []; - }); - - $app.methods.refreshStickerTable = function () { - this.galleryDialogStickersLoading = true; - var params = { - n: 100, - tag: 'sticker' - }; - vrcPlusIconRequest.getFileList(params).finally(() => { - this.galleryDialogStickersLoading = false; - }); - }; - - API.$on('FILES:LIST', function (args) { - if (args.params.tag === 'sticker') { - $app.stickerTable = args.json.reverse(); - } - }); - - $app.methods.displayStickerUpload = function () { - document.getElementById('StickerUploadButton').click(); - }; - - API.$on('STICKER:ADD', function (args) { - if (Object.keys($app.stickerTable).length !== 0) { - $app.stickerTable.unshift(args.json); - } - }); - - $app.data.instanceStickersCache = []; - - $app.methods.trySaveStickerToFile = async function ( - displayName, - userId, - inventoryId - ) { - if (this.instanceStickersCache.includes(inventoryId)) { - return; - } - this.instanceStickersCache.push(inventoryId); - if (this.instanceStickersCache.size > 100) { - this.instanceStickersCache.shift(); - } - var args = await inventoryRequest.getUserInventoryItem({ - inventoryId, - userId - }); - - if ( - args.json.itemType !== 'sticker' || - !args.json.flags.includes('ugc') - ) { - // Not a sticker or ugc, skipping - return; - } - - var imageUrl = args.json.metadata?.imageUrl ?? args.json.imageUrl; - var createdAt = args.json.created_at; - var monthFolder = createdAt.slice(0, 7); - var fileNameDate = createdAt - .replace(/:/g, '-') - .replace(/T/g, '_') - .replace(/Z/g, ''); - var fileName = `${displayName}_${fileNameDate}_${inventoryId}.png`; - var filePath = await AppApi.SaveStickerToFile( - imageUrl, - this.ugcFolderPath, - monthFolder, - fileName - ); - if (filePath) { - console.log(`Sticker saved to file: ${monthFolder}\\${fileName}`); - } - }; - - // #endregion - // #region | Emoji - - $app.data.instanceInventoryCache = []; - $app.data.instanceInventoryQueue = []; - $app.data.instanceInventoryQueueWorker = null; - - $app.methods.queueCheckInstanceInventory = function (inventoryId, userId) { - if ( - this.instanceInventoryCache.includes(inventoryId) || - this.instanceStickersCache.includes(inventoryId) - ) { - return; - } - this.instanceInventoryCache.push(inventoryId); - if (this.instanceInventoryCache.length > 100) { - this.instanceInventoryCache.shift(); - } - - this.instanceInventoryQueue.push({ inventoryId, userId }); - - if (!this.instanceInventoryQueueWorker) { - this.instanceInventoryQueueWorker = workerTimers.setInterval(() => { - const item = this.instanceInventoryQueue.shift(); - if (item?.inventoryId) { - this.trySaveEmojiToFile(item.inventoryId, item.userId); - } - }, 2_500); - } - }; - - $app.methods.trySaveEmojiToFile = async function (inventoryId, userId) { - const args = await inventoryRequest.getUserInventoryItem({ - inventoryId, - userId - }); - - if ( - args.json.itemType !== 'emoji' || - !args.json.flags.includes('ugc') - ) { - // Not an emoji or ugc, skipping - return; - } - - const userArgs = await userRequest.getCachedUser({ - userId: args.json.holderId - }); - const displayName = userArgs.json?.displayName ?? ''; - - let emoji = args.json.metadata; - emoji.name = `${displayName}_${inventoryId}`; - - const emojiFileName = getEmojiFileName(emoji); - const imageUrl = args.json.metadata?.imageUrl ?? args.json.imageUrl; - const createdAt = args.json.created_at; - const monthFolder = createdAt.slice(0, 7); - - const filePath = await AppApi.SaveEmojiToFile( - imageUrl, - this.ugcFolderPath, - monthFolder, - emojiFileName - ); - if (filePath) { - console.log( - `Emoji saved to file: ${monthFolder}\\${emojiFileName}` - ); - } - - if (this.instanceInventoryQueue.length === 0) { - workerTimers.clearInterval(this.instanceInventoryQueueWorker); - this.instanceInventoryQueueWorker = null; - } - }; - - // #endregion - // #region | Prints - $app.methods.cropPrintsChanged = function () { - if (!this.cropInstancePrints) return; - this.$confirm( - $t( - 'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old' - ), - { - confirmButtonText: $t( - 'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old_confirm' - ), - cancelButtonText: $t( - 'view.settings.advanced.advanced.save_instance_prints_to_file.crop_convert_old_cancel' - ), - type: 'info', - showInput: false, - callback: async (action) => { - if (action === 'confirm') { - var msgBox = this.$message({ - message: 'Batch print cropping in progress...', - type: 'warning', - duration: 0 - }); - try { - await AppApi.CropAllPrints(this.ugcFolderPath); - this.$message({ - message: 'Batch print cropping complete', - type: 'success' - }); - } catch (err) { - console.error(err); - this.$message({ - message: `Batch print cropping failed: ${err}`, - type: 'error' - }); - } finally { - msgBox.close(); - } - } - } - } - ); - }; - - API.$on('LOGIN', function () { - $app.printTable = []; - if ($app.autoDeleteOldPrints) { - $app.tryDeleteOldPrints(); - } - }); - - $app.methods.refreshPrintTable = async function () { - this.galleryDialogPrintsLoading = true; - var params = { - n: 100 - }; - const args = await vrcPlusImageRequest.getPrints(params).finally(() => { - this.galleryDialogPrintsLoading = false; - }); - args.json.sort((a, b) => { - return new Date(b.timestamp) - new Date(a.timestamp); - }); - $app.printTable = args.json; - }; - - $app.data.printUploadNote = ''; - $app.data.printCropBorder = true; - - $app.data.saveInstancePrints = await configRepository.getBool( - 'VRCX_saveInstancePrints', - false - ); - - $app.data.cropInstancePrints = await configRepository.getBool( - 'VRCX_cropInstancePrints', - false - ); - - $app.data.saveInstanceStickers = await configRepository.getBool( - 'VRCX_saveInstanceStickers', - false - ); - - $app.data.saveInstanceEmoji = await configRepository.getBool( - 'VRCX_saveInstanceEmoji', - false - ); - - $app.data.printCache = []; - $app.data.printQueue = []; - $app.data.printQueueWorker = null; - - $app.methods.queueSavePrintToFile = function (printId) { - if (this.printCache.includes(printId)) { - return; - } - this.printCache.push(printId); - if (this.printCache.length > 100) { - this.printCache.shift(); - } - - this.printQueue.push(printId); - - if (!this.printQueueWorker) { - this.printQueueWorker = workerTimers.setInterval(() => { - let printId = this.printQueue.shift(); - if (printId) { - this.trySavePrintToFile(printId); - } - }, 2_500); - } - }; - - $app.methods.trySavePrintToFile = async function (printId) { - var args = await vrcPlusImageRequest.getPrint({ printId }); - var imageUrl = args.json?.files?.image; - if (!imageUrl) { - console.error('Print image URL is missing', args); - return; - } - var print = args.json; - var createdAt = getPrintLocalDate(print); - try { - var owner = await userRequest.getCachedUser({ - userId: print.ownerId - }); - console.log( - `Print spawned by ${owner?.json?.displayName} id:${print.id} note:${print.note} authorName:${print.authorName} at:${new Date().toISOString()}` - ); - } catch (err) { - console.error(err); - } - var monthFolder = createdAt.toISOString().slice(0, 7); - var fileName = getPrintFileName(print); - var filePath = await AppApi.SavePrintToFile( - imageUrl, - this.ugcFolderPath, - monthFolder, - fileName - ); - if (filePath) { - console.log(`Print saved to file: ${monthFolder}\\${fileName}`); - if (this.cropInstancePrints) { - if (!(await AppApi.CropPrintImage(filePath))) { - console.error('Failed to crop print image'); - } - } - } - - if (this.printQueue.length === 0) { - workerTimers.clearInterval(this.printQueueWorker); - this.printQueueWorker = null; - } - }; - - // #endregion - // #region | Emoji - - API.$on('LOGIN', function () { - $app.emojiTable = []; - }); - - $app.methods.refreshEmojiTable = function () { - this.galleryDialogEmojisLoading = true; - var params = { - n: 100, - tag: 'emoji' - }; - vrcPlusIconRequest.getFileList(params).finally(() => { - this.galleryDialogEmojisLoading = false; - }); - }; - - API.$on('FILES:LIST', function (args) { - if (args.params.tag === 'emoji') { - $app.emojiTable = args.json.reverse(); - } - }); - - API.$on('EMOJI:ADD', function (args) { - if (Object.keys($app.emojiTable).length !== 0) { - $app.emojiTable.unshift(args.json); - } - }); - - // #endregion - // #region Misc - - $app.methods.removeEmojis = function (text) { - if (!text) { - return ''; - } - return text - .replace( - /([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g, - '' - ) - .replace(/\s+/g, ' ') - .trim(); - }; - - $app.methods.checkCanInvite = function (location) { - var L = parseLocation(location); - var instance = API.cachedInstances.get(location); - if (instance?.closedAt) { - return false; - } - if ( - L.accessType === 'public' || - L.accessType === 'group' || - L.userId === API.currentUser.id - ) { - return true; - } - if (L.accessType === 'invite' || L.accessType === 'friends') { - return false; - } - if (this.lastLocation.location === location) { - return true; - } - return false; - }; - - $app.methods.checkCanInviteSelf = function (location) { - var L = parseLocation(location); - var instance = API.cachedInstances.get(location); - if (instance?.closedAt) { - return false; - } - if (L.userId === API.currentUser.id) { - return true; - } - if (L.accessType === 'friends' && !this.friends.has(L.userId)) { - return false; - } - return true; - }; - - $app.methods.setAsideWidth = async function () { - await configRepository.setInt('VRCX_sidePanelWidth', this.asideWidth); - }; - - /** - * @param {object} user - User Ref Object - * @param {boolean} isIcon - is use for icon (about 40x40) - * @param {string} resolution - requested icon resolution (default 128), - * @param {boolean} isUserDialogIcon - is use for user dialog icon - * @returns {string} - img url - * - * VRC's 64 scaling doesn't look good, 128 is better, but some images might be overly sharp. - * 128 is smaller than 256 or the original image size, making it a good choice. - * - * TODO: code is messy cause I haven't figured out the img field, maybe refactor it later - */ - $app.methods.userImage = function ( - user, - isIcon, - resolution = '128', - isUserDialogIcon = false - ) { - if (!user) { - return ''; - } - if ( - (isUserDialogIcon && user.userIcon) || - (this.displayVRCPlusIconsAsAvatar && user.userIcon) - ) { - if (isIcon) { - return convertFileUrlToImageUrl(user.userIcon); - } - return user.userIcon; - } - - if (user.profilePicOverrideThumbnail) { - if (isIcon) { - return user.profilePicOverrideThumbnail.replace( - '/256', - `/${resolution}` - ); - } - return user.profilePicOverrideThumbnail; - } - if (user.profilePicOverride) { - return user.profilePicOverride; - } - if (user.thumbnailUrl) { - return user.thumbnailUrl; - } - if (user.currentAvatarThumbnailImageUrl) { - if (isIcon) { - return user.currentAvatarThumbnailImageUrl.replace( - '/256', - `/${resolution}` - ); - } - return user.currentAvatarThumbnailImageUrl; - } - if (user.currentAvatarImageUrl) { - if (isIcon) { - return convertFileUrlToImageUrl(user.currentAvatarImageUrl); - } - return user.currentAvatarImageUrl; - } - return ''; - }; - - $app.methods.userImageFull = function (user) { - if (this.displayVRCPlusIconsAsAvatar && user.userIcon) { - return user.userIcon; - } - if (user.profilePicOverride) { - return user.profilePicOverride; - } - return user.currentAvatarImageUrl; - }; - - $app.methods.getImageUrlFromImageId = function (imageId) { - return `https://api.vrchat.cloud/api/1/file/${imageId}/1/`; - }; - - $app.methods.showConsole = function () { - AppApi.ShowDevTools(); - if ( - this.debug || - this.debugWebRequests || - this.debugWebSocket || - this.debugUserDiff - ) { - return; - } - console.log( - '%cCareful! This might not do what you think.', - 'background-color: red; color: yellow; font-size: 32px; font-weight: bold' - ); - console.log( - '%cIf someone told you to copy-paste something here, it can give them access to your account.', - 'font-size: 20px;' - ); - }; - - $app.methods.clearVRCXCache = function () { - API.failedGetRequests = new Map(); - API.cachedUsers.forEach((ref, id) => { - if ( - !this.friends.has(id) && - !this.lastLocation.playerList.has(ref.id) && - id !== API.currentUser.id - ) { - API.cachedUsers.delete(id); - } - }); - API.cachedWorlds.forEach((ref, id) => { - if ( - !API.cachedFavoritesByObjectId.has(id) && - ref.authorId !== API.currentUser.id && - !this.localWorldFavoritesList.includes(id) - ) { - API.cachedWorlds.delete(id); - } - }); - API.cachedAvatars.forEach((ref, id) => { - if ( - !API.cachedFavoritesByObjectId.has(id) && - ref.authorId !== API.currentUser.id && - !this.localAvatarFavoritesList.includes(id) && - !$app.avatarHistory.has(id) - ) { - API.cachedAvatars.delete(id); - } - }); - API.cachedGroups.forEach((ref, id) => { - if (!API.currentUserGroups.has(id)) { - API.cachedGroups.delete(id); - } - }); - API.cachedInstances.forEach((ref, id) => { - // delete instances over an hour old - if (Date.parse(ref.$fetchedAt) < Date.now() - 3600000) { - API.cachedInstances.delete(id); - } - }); - API.cachedAvatarNames = new Map(); - this.customUserTags = new Map(); - this.updateInstanceInfo = 0; - }; - - $app.data.sqliteTableSizes = {}; - - $app.methods.getSqliteTableSizes = async function () { - this.sqliteTableSizes = { - gps: await database.getGpsTableSize(), - status: await database.getStatusTableSize(), - bio: await database.getBioTableSize(), - avatar: await database.getAvatarTableSize(), - onlineOffline: await database.getOnlineOfflineTableSize(), - friendLogHistory: await database.getFriendLogHistoryTableSize(), - notification: await database.getNotificationTableSize(), - location: await database.getLocationTableSize(), - joinLeave: await database.getJoinLeaveTableSize(), - portalSpawn: await database.getPortalSpawnTableSize(), - videoPlay: await database.getVideoPlayTableSize(), - event: await database.getEventTableSize(), - external: await database.getExternalTableSize() - }; - }; - - $app.data.ipcEnabled = false; - $app.methods.ipcEvent = function (json) { - if (!API.isLoggedIn) { - return; - } - try { - var data = JSON.parse(json); - } catch { - console.log(`IPC invalid JSON, ${json}`); - return; - } - switch (data.type) { - case 'OnEvent': - if (!this.isGameRunning) { - console.log('Game closed, skipped event', data); - return; - } - if (this.debugPhotonLogging) { - console.log( - 'OnEvent', - data.OnEventData.Code, - data.OnEventData - ); - } - this.parsePhotonEvent(data.OnEventData, data.dt); - this.photonEventPulse(); - break; - case 'OnOperationResponse': - if (!this.isGameRunning) { - console.log('Game closed, skipped event', data); - return; - } - if (this.debugPhotonLogging) { - console.log( - 'OnOperationResponse', - data.OnOperationResponseData.OperationCode, - data.OnOperationResponseData - ); - } - this.parseOperationResponse( - data.OnOperationResponseData, - data.dt - ); - this.photonEventPulse(); - break; - case 'OnOperationRequest': - if (!this.isGameRunning) { - console.log('Game closed, skipped event', data); - return; - } - if (this.debugPhotonLogging) { - console.log( - 'OnOperationRequest', - data.OnOperationRequestData.OperationCode, - data.OnOperationRequestData - ); - } - break; - case 'VRCEvent': - if (!this.isGameRunning) { - console.log('Game closed, skipped event', data); - return; - } - this.parseVRCEvent(data); - this.photonEventPulse(); - break; - case 'Event7List': - this.photonEvent7List.clear(); - for (var [id, dt] of Object.entries(data.Event7List)) { - this.photonEvent7List.set(parseInt(id, 10), dt); - } - this.photonLastEvent7List = Date.parse(data.dt); - break; - case 'VrcxMessage': - if (this.debugPhotonLogging) { - console.log('VrcxMessage:', data); - } - this.eventVrcxMessage(data); - break; - case 'Ping': - if (!this.photonLoggingEnabled) { - this.photonLoggingEnabled = true; - configRepository.setBool('VRCX_photonLoggingEnabled', true); - } - this.ipcEnabled = true; - this.ipcTimeout = 60; // 30secs - break; - case 'MsgPing': - this.externalNotifierVersion = data.version; - break; - case 'LaunchCommand': - this.eventLaunchCommand(data.command); - break; - case 'VRCXLaunch': - console.log('VRCXLaunch:', data); - break; - default: - console.log('IPC:', data); - } - }; - - $app.data.externalNotifierVersion = 0; - $app.data.photonEventCount = 0; - $app.data.photonEventIcon = false; - $app.data.customUserTags = new Map(); - - $app.methods.addCustomTag = function (data) { - if (data.Tag) { - this.customUserTags.set(data.UserId, { - tag: data.Tag, - colour: data.TagColour - }); - } else { - this.customUserTags.delete(data.UserId); - } - var feedUpdate = { - userId: data.UserId, - colour: data.TagColour - }; - AppApi.ExecuteVrOverlayFunction( - 'updateHudFeedTag', - JSON.stringify(feedUpdate) - ); - var ref = API.cachedUsers.get(data.UserId); - if (typeof ref !== 'undefined') { - ref.$customTag = data.Tag; - ref.$customTagColour = data.TagColour; - } - this.updateSharedFeed(true); - }; - - $app.methods.eventVrcxMessage = function (data) { - switch (data.MsgType) { - case 'CustomTag': - this.addCustomTag(data); - break; - case 'ClearCustomTags': - this.customUserTags.forEach((value, key) => { - this.customUserTags.delete(key); - var ref = API.cachedUsers.get(key); - if (typeof ref !== 'undefined') { - ref.$customTag = ''; - ref.$customTagColour = ''; - } - }); - break; - case 'Noty': - if ( - this.photonLoggingEnabled || - (this.externalNotifierVersion && - this.externalNotifierVersion > 21) - ) { - return; - } - var entry = { - created_at: new Date().toJSON(), - type: 'Event', - data: data.Data - }; - database.addGamelogEventToDatabase(entry); - this.queueGameLogNoty(entry); - this.addGameLog(entry); - break; - case 'External': - var displayName = data.DisplayName ?? ''; - var entry = { - created_at: new Date().toJSON(), - type: 'External', - message: data.Data, - displayName, - userId: data.UserId, - location: this.lastLocation.location - }; - database.addGamelogExternalToDatabase(entry); - this.queueGameLogNoty(entry); - this.addGameLog(entry); - break; - default: - console.log('VRCXMessage:', data); - break; - } - }; - - $app.methods.photonEventPulse = function () { - this.photonEventCount++; - this.photonEventIcon = true; - workerTimers.setTimeout(() => (this.photonEventIcon = false), 150); - }; - - $app.methods.parseOperationResponse = function (data, dateTime) { - switch (data.OperationCode) { - case 226: - if ( - typeof data.Parameters[248] !== 'undefined' && - typeof data.Parameters[248][248] !== 'undefined' - ) { - this.setPhotonLobbyMaster(data.Parameters[248][248]); - } - if (typeof data.Parameters[254] !== 'undefined') { - this.photonLobbyCurrentUser = data.Parameters[254]; - } - if (typeof data.Parameters[249] !== 'undefined') { - for (var i in data.Parameters[249]) { - var id = parseInt(i, 10); - var user = data.Parameters[249][i]; - this.parsePhotonUser(id, user.user, dateTime); - this.parsePhotonAvatarChange( - id, - user.user, - user.avatarDict, - dateTime - ); - this.parsePhotonGroupChange( - id, - user.user, - user.groupOnNameplate, - dateTime - ); - this.parsePhotonAvatar(user.avatarDict); - this.parsePhotonAvatar(user.favatarDict); - var hasInstantiated = false; - var lobbyJointime = this.photonLobbyJointime.get(id); - if (typeof lobbyJointime !== 'undefined') { - hasInstantiated = lobbyJointime.hasInstantiated; - } - this.photonLobbyJointime.set(id, { - joinTime: Date.parse(dateTime), - hasInstantiated, - inVRMode: user.inVRMode, - avatarEyeHeight: user.avatarEyeHeight, - canModerateInstance: user.canModerateInstance, - groupOnNameplate: user.groupOnNameplate, - showGroupBadgeToOthers: user.showGroupBadgeToOthers, - showSocialRank: user.showSocialRank, - useImpostorAsFallback: user.useImpostorAsFallback, - platform: user.platform - }); - } - } - if (typeof data.Parameters[252] !== 'undefined') { - this.parsePhotonLobbyIds(data.Parameters[252]); - } - this.photonEvent7List = new Map(); - break; - } - }; - - API.$on('LOGIN', async function () { - var command = await AppApi.GetLaunchCommand(); - if (command) { - $app.eventLaunchCommand(command); - } - }); - - $app.methods.eventLaunchCommand = function (input) { - if (!API.isLoggedIn) { - return; - } - console.log('LaunchCommand:', input); - var args = input.split('/'); - var command = args[0]; - var commandArg = args[1]?.trim(); - var shouldFocusWindow = true; - switch (command) { - case 'world': - this.directAccessWorld(input.replace('world/', '')); - break; - case 'avatar': - this.showAvatarDialog(commandArg); - break; - case 'user': - this.showUserDialog(commandArg); - break; - case 'group': - this.showGroupDialog(commandArg); - break; - case 'local-favorite-world': - console.log('local-favorite-world', commandArg); - var [id, group] = commandArg.split(':'); - worldRequest.getCachedWorld({ worldId: id }).then((args1) => { - this.directAccessWorld(id); - this.addLocalWorldFavorite(id, group); - return args1; - }); - break; - case 'addavatardb': - this.addAvatarProvider(input.replace('addavatardb/', '')); - break; - case 'switchavatar': - var avatarId = commandArg; - var regexAvatarId = - /avtr_[0-9A-Fa-f]{8}-([0-9A-Fa-f]{4}-){3}[0-9A-Fa-f]{12}/g; - if (!avatarId.match(regexAvatarId) || avatarId.length !== 41) { - this.$message({ - message: 'Invalid Avatar ID', - type: 'error' - }); - break; - } - if (this.showConfirmationOnSwitchAvatar) { - this.selectAvatarWithConfirmation(avatarId); - // Makes sure the window is focused - shouldFocusWindow = true; - } else { - this.selectAvatarWithoutConfirmation(avatarId); - shouldFocusWindow = false; - } - break; - case 'import': - var type = args[1]; - if (!type) break; - var data = input.replace(`import/${type}/`, ''); - if (type === 'avatar') { - this.avatarImportDialogInput = data; - this.showAvatarImportDialog(); - } else if (type === 'world') { - this.worldImportDialogInput = data; - this.showWorldImportDialog(); - } else if (type === 'friend') { - this.friendImportDialogInput = data; - this.showFriendImportDialog(); - } - break; - } - if (shouldFocusWindow) { - AppApi.FocusWindow(); - } - }; - - $app.methods.toggleAllowBooping = function () { - userRequest - .saveCurrentUser({ - isBoopingEnabled: !API.currentUser.isBoopingEnabled - }) - .then((args) => { - return args; - }); - }; - - // #endregion - // #region | App: Previous Instances Info Dialog - - $app.data.previousInstancesInfoDialogVisible = false; - $app.data.previousInstancesInfoDialogInstanceId = ''; - - $app.methods.showPreviousInstancesInfoDialog = function (instanceId) { - this.previousInstancesInfoDialogVisible = true; - this.previousInstancesInfoDialogInstanceId = instanceId; - }; - - $app.data.dtHour12 = await configRepository.getBool('VRCX_dtHour12', false); - $app.data.dtIsoFormat = await configRepository.getBool( - 'VRCX_dtIsoFormat', - false - ); - $app.methods.setDatetimeFormat = async function (setIsoFormat = false) { - if (setIsoFormat) { - this.dtIsoFormat = !this.dtIsoFormat; - } - var currentCulture = await AppApi.CurrentCulture(); - var hour12 = await configRepository.getBool('VRCX_dtHour12'); - var isoFormat = await configRepository.getBool('VRCX_dtIsoFormat'); - if (typeof this.dtHour12 !== 'undefined') { - if (hour12 !== this.dtHour12) { - await configRepository.setBool('VRCX_dtHour12', this.dtHour12); - this.updateVRConfigVars(); - } - var hour12 = this.dtHour12; - } - if (typeof this.dtIsoFormat !== 'undefined') { - if (isoFormat !== this.dtIsoFormat) { - await configRepository.setBool( - 'VRCX_dtIsoFormat', - this.dtIsoFormat - ); - } - var isoFormat = this.dtIsoFormat; - } - var formatDate1 = function (date, format) { - if (!date) { - return '-'; - } - var dt = new Date(date); - if (format === 'long') { - return dt.toLocaleDateString(currentCulture, { - month: '2-digit', - day: '2-digit', - year: 'numeric', - hour: 'numeric', - minute: 'numeric', - second: 'numeric', - hourCycle: hour12 ? 'h12' : 'h23' - }); - } else if (format === 'short') { - return dt - .toLocaleDateString(currentCulture, { - month: '2-digit', - day: '2-digit', - hour: 'numeric', - minute: 'numeric', - hourCycle: hour12 ? 'h12' : 'h23' - }) - .replace(' AM', 'am') - .replace(' PM', 'pm') - .replace(',', ''); - } - return '-'; - }; - if (isoFormat) { - formatDate1 = function (date, format) { - if (!date) { - return '-'; - } - const dt = new Date(date); - if (format === 'long') { - const formatDate = (date) => { - const padZero = (num) => String(num).padStart(2, '0'); - - const year = date.getFullYear(); - const month = padZero(date.getMonth() + 1); - const day = padZero(date.getDate()); - const hours = padZero(date.getHours()); - const minutes = padZero(date.getMinutes()); - const seconds = padZero(date.getSeconds()); - - return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; - }; - - return formatDate(dt); - } else if (format === 'short') { - return dt - .toLocaleDateString('en-nz', { - month: '2-digit', - day: '2-digit', - hour: 'numeric', - minute: 'numeric', - hourCycle: hour12 ? 'h12' : 'h23' - }) - .replace(' AM', 'am') - .replace(' PM', 'pm') - .replace(',', ''); - } - return '-'; - }; - } - Vue.filter('formatDate', formatDate1); - }; - $app.methods.setDatetimeFormat(); - - $app.data.enableCustomEndpoint = await configRepository.getBool( - 'VRCX_enableCustomEndpoint', - false - ); - $app.methods.toggleCustomEndpoint = async function () { - await configRepository.setBool( - 'VRCX_enableCustomEndpoint', - this.enableCustomEndpoint - ); - this.loginForm.endpoint = ''; - this.loginForm.websocket = ''; - }; - - $app.methods.getNameColour = async function (userId) { - var hue = await AppApi.GetColourFromUserID(userId); - return this.HueToHex(hue); - }; - - $app.methods.userColourInit = async function () { - var dictObject = await AppApi.GetColourBulk( - Array.from(API.cachedUsers.keys()) - ); - if (LINUX) { - dictObject = Object.fromEntries(dictObject); - } - for (var [userId, hue] of Object.entries(dictObject)) { - var ref = API.cachedUsers.get(userId); - if (typeof ref !== 'undefined') { - ref.$userColour = this.HueToHex(hue); - } - } - }; - - $app.methods.HueToHex = function (hue) { - // this.HSVtoRGB(hue / 65535, .8, .8); - if (this.isDarkMode) { - return this.HSVtoRGB(hue / 65535, 0.6, 1); - } - return this.HSVtoRGB(hue / 65535, 1, 0.7); - }; - - $app.methods.HSVtoRGB = function (h, s, v) { - var r = 0; - var g = 0; - var b = 0; - if (arguments.length === 1) { - var s = h.s; - var v = h.v; - var h = h.h; - } - var i = Math.floor(h * 6); - var f = h * 6 - i; - var p = v * (1 - s); - var q = v * (1 - f * s); - var t = v * (1 - (1 - f) * s); - switch (i % 6) { - case 0: - r = v; - g = t; - b = p; - break; - case 1: - r = q; - g = v; - b = p; - break; - case 2: - r = p; - g = v; - b = t; - break; - case 3: - r = p; - g = q; - b = v; - break; - case 4: - r = t; - g = p; - b = v; - break; - case 5: - r = v; - g = p; - b = q; - break; - } - var red = Math.round(r * 255); - var green = Math.round(g * 255); - var blue = Math.round(b * 255); - var decColor = 0x1000000 + blue + 0x100 * green + 0x10000 * red; - return `#${decColor.toString(16).substr(1)}`; - }; - - $app.methods.onPlayerTraveling = function (ref) { - if ( - !this.isGameRunning || - !this.lastLocation.location || - this.lastLocation.location !== ref.travelingToLocation || - ref.id === API.currentUser.id || - this.lastLocation.playerList.has(ref.id) - ) { - return; - } - - var onPlayerJoining = { - created_at: new Date(ref.created_at).toJSON(), - userId: ref.id, - displayName: ref.displayName, - type: 'OnPlayerJoining' - }; - this.queueFeedNoty(onPlayerJoining); - }; - - $app.methods.updateCurrentUserLocation = function () { - var ref = API.cachedUsers.get(API.currentUser.id); - if (typeof ref === 'undefined') { - return; - } - - // update cached user with both gameLog and API locations - var currentLocation = API.currentUser.$locationTag; - var L = parseLocation(currentLocation); - if (L.isTraveling) { - currentLocation = API.currentUser.$travelingToLocation; - } - ref.location = API.currentUser.$locationTag; - ref.travelingToLocation = API.currentUser.$travelingToLocation; - - if ( - this.isGameRunning && - !this.gameLogDisabled && - this.lastLocation.location !== '' - ) { - // use gameLog instead of API when game is running - currentLocation = this.lastLocation.location; - if (this.lastLocation.location === 'traveling') { - currentLocation = this.lastLocationDestination; - } - ref.location = this.lastLocation.location; - ref.travelingToLocation = this.lastLocationDestination; - } - - ref.$online_for = API.currentUser.$online_for; - ref.$offline_for = API.currentUser.$offline_for; - ref.$location = parseLocation(currentLocation); - if (!this.isGameRunning || this.gameLogDisabled) { - ref.$location_at = API.currentUser.$location_at; - ref.$travelingToTime = API.currentUser.$travelingToTime; - this.applyUserDialogLocation(); - this.applyWorldDialogInstances(); - this.applyGroupDialogInstances(); - } else { - ref.$location_at = this.lastLocation.date; - ref.$travelingToTime = this.lastLocationDestinationTime; - API.currentUser.$travelingToTime = this.lastLocationDestinationTime; - } - }; - - $app.methods.setCurrentUserLocation = async function ( - location, - travelingToLocation - ) { - API.currentUser.$location_at = Date.now(); - API.currentUser.$travelingToTime = Date.now(); - API.currentUser.$locationTag = location; - API.currentUser.$travelingToLocation = travelingToLocation; - this.updateCurrentUserLocation(); - - // janky gameLog support for Quest - if (this.isGameRunning) { - // with the current state of things, lets not run this if we don't need to - return; - } - var lastLocation = ''; - for (var i = this.gameLogSessionTable.length - 1; i > -1; i--) { - var item = this.gameLogSessionTable[i]; - if (item.type === 'Location') { - lastLocation = item.location; - break; - } - } - if (lastLocation === location) { - return; - } - this.lastLocationDestination = ''; - this.lastLocationDestinationTime = 0; - - if (isRealInstance(location)) { - var dt = new Date().toJSON(); - var L = parseLocation(location); - - this.lastLocation.location = location; - this.lastLocation.date = dt; - - var entry = { - created_at: dt, - type: 'Location', - location, - worldId: L.worldId, - worldName: await this.getWorldName(L.worldId), - groupName: await this.getGroupName(L.groupId), - time: 0 - }; - database.addGamelogLocationToDatabase(entry); - this.queueGameLogNoty(entry); - this.addGameLog(entry); - this.addInstanceJoinHistory(location, dt); - - this.applyUserDialogLocation(); - this.applyWorldDialogInstances(); - this.applyGroupDialogInstances(); - } else { - this.lastLocation.location = ''; - this.lastLocation.date = ''; - } - }; - - $app.data.avatarHistory = new Set(); - $app.data.avatarHistoryArray = []; - - $app.methods.getAvatarHistory = async function () { - this.avatarHistory = new Set(); - var historyArray = await database.getAvatarHistory(API.currentUser.id); - this.avatarHistoryArray = historyArray; - for (var i = 0; i < historyArray.length; i++) { - var avatar = historyArray[i]; - if (avatar.authorId === API.currentUser.id) { - continue; - } - this.avatarHistory.add(avatar.id); - API.applyAvatar(avatar); - } - }; - - $app.methods.addAvatarToHistory = function (avatarId) { - avatarRequest.getAvatar({ avatarId }).then((args) => { - var { ref } = args; - - database.addAvatarToCache(ref); - database.addAvatarToHistory(ref.id); - - if (ref.authorId === API.currentUser.id) { - return; - } - - var historyArray = this.avatarHistoryArray; - for (var i = 0; i < historyArray.length; ++i) { - if (historyArray[i].id === ref.id) { - historyArray.splice(i, 1); - } - } - - this.avatarHistoryArray.unshift(ref); - this.avatarHistory.delete(ref.id); - this.avatarHistory.add(ref.id); - }); - }; - - $app.methods.addAvatarWearTime = function (avatarId) { - if (!API.currentUser.$previousAvatarSwapTime || !avatarId) { - return; - } - const timeSpent = Date.now() - API.currentUser.$previousAvatarSwapTime; - database.addAvatarTimeSpent(avatarId, timeSpent); - }; - - $app.methods.promptClearAvatarHistory = function () { - this.$confirm('Continue? Clear Avatar History', 'Confirm', { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - callback: (action) => { - if (action === 'confirm') { - this.clearAvatarHistory(); - } - } - }); - }; - - $app.methods.clearAvatarHistory = function () { - this.avatarHistory = new Set(); - this.avatarHistoryArray = []; - database.clearAvatarHistory(); - }; - - $app.data.databaseVersion = await configRepository.getInt( - 'VRCX_databaseVersion', - 0 - ); - - $app.methods.updateDatabaseVersion = async function () { - var databaseVersion = 12; - if (this.databaseVersion < databaseVersion) { - if (this.databaseVersion) { - var msgBox = this.$message({ - message: - 'DO NOT CLOSE VRCX, database upgrade in progress...', - type: 'warning', - duration: 0 - }); - } - console.log( - `Updating database from ${this.databaseVersion} to ${databaseVersion}...` - ); - try { - await database.cleanLegendFromFriendLog(); // fix friendLog spammed with crap - await database.fixGameLogTraveling(); // fix bug with gameLog location being set as traveling - await database.fixNegativeGPS(); // fix GPS being a negative value due to VRCX bug with traveling - await database.fixBrokenLeaveEntries(); // fix user instance timer being higher than current user location timer - await database.fixBrokenGroupInvites(); // fix notification v2 in wrong table - await database.fixBrokenNotifications(); // fix notifications being null - await database.fixBrokenGroupChange(); // fix spam group left & name change - await database.fixCancelFriendRequestTypo(); // fix CancelFriendRequst typo - await database.fixBrokenGameLogDisplayNames(); // fix gameLog display names "DisplayName (userId)" - await database.upgradeDatabaseVersion(); // update database version - await database.vacuum(); // succ - await database.optimize(); - await configRepository.setInt( - 'VRCX_databaseVersion', - databaseVersion - ); - console.log('Database update complete.'); - msgBox?.close(); - if (this.databaseVersion) { - // only display when database exists - this.$message({ - message: 'Database upgrade complete', - type: 'success' - }); - } - this.databaseVersion = databaseVersion; - } catch (err) { - console.error(err); - msgBox?.close(); - this.$message({ - message: - 'Database upgrade failed, check console for details', - type: 'error', - duration: 120000 - }); - AppApi.ShowDevTools(); - } - } - }; - - // #endregion - // #region | App: world favorite import - - $app.data.worldImportDialogVisible = false; - $app.data.worldImportDialogInput = ''; - $app.methods.showWorldImportDialog = function () { - this.worldImportDialogVisible = true; - }; - - // #endregion - // #region | App: avatar favorite import - - $app.data.avatarImportDialogVisible = false; - $app.data.avatarImportDialogInput = ''; - $app.methods.showAvatarImportDialog = function () { - this.avatarImportDialogVisible = true; - }; - - // #endregion - // #region | App: friend favorite import - $app.data.friendImportDialogVisible = false; - $app.data.friendImportDialogInput = ''; - $app.methods.showFriendImportDialog = function () { - this.friendImportDialogVisible = true; - }; - - // #endregion - // #region | App: note export - - $app.data.isNoteExportDialogVisible = false; - - $app.methods.showNoteExportDialog = function () { - this.isNoteExportDialogVisible = true; - }; - - // user generated content - $app.data.ugcFolderPath = await configRepository.getString( - 'VRCX_userGeneratedContentPath', - '' - ); - - $app.data.folderSelectorDialogVisible = false; - - $app.methods.setUGCFolderPath = async function (path) { - if (typeof path !== 'string') { - path = ''; - } - await configRepository.setString('VRCX_userGeneratedContentPath', path); - this.ugcFolderPath = path; - }; - - $app.methods.resetUGCFolder = function () { - this.setUGCFolderPath(''); - }; - - $app.methods.openUGCFolder = async function () { - if (LINUX && this.ugcFolderPath == null) { - this.resetUGCFolder(); - } - await AppApi.OpenUGCPhotosFolder(this.ugcFolderPath); - }; - - $app.methods.folderSelectorDialog = async function (oldPath) { - if (this.folderSelectorDialogVisible) return; - if (!oldPath) { - oldPath = ''; - } - - this.folderSelectorDialogVisible = true; - var newFolder = ''; - if (LINUX) { - newFolder = await window.electron.openDirectoryDialog(); - } else { - newFolder = await AppApi.OpenFolderSelectorDialog(oldPath); - } - - this.folderSelectorDialogVisible = false; - return newFolder; - }; - - $app.methods.openUGCFolderSelector = async function () { - var path = await this.folderSelectorDialog(this.ugcFolderPath); - await this.setUGCFolderPath(path); - }; - - // auto delete old prints - - $app.data.autoDeleteOldPrints = await configRepository.getBool( - 'VRCX_autoDeleteOldPrints', - false - ); - - $app.methods.tryDeleteOldPrints = async function () { - await this.refreshPrintTable(); - const printLimit = 64 - 2; // 2 reserved for new prints - const printCount = $app.printTable.length; - if (printCount <= printLimit) { - return; - } - const deleteCount = printCount - printLimit; - if (deleteCount <= 0) { - return; - } - let idList = []; - for (let i = 0; i < deleteCount; i++) { - const print = $app.printTable[printCount - 1 - i]; - idList.push(print.id); - } - console.log(`Deleting ${deleteCount} old prints`, idList); - try { - for (const printId of idList) { - await vrcPlusImageRequest.deletePrint(printId); - var text = `Old print automaticly deleted: ${printId}`; - if (this.errorNoty) { - this.errorNoty.close(); - } - this.errorNoty = new Noty({ - type: 'info', - text - }).show(); - } - } catch (err) { - console.error('Failed to delete old print:', err); - } - await this.refreshPrintTable(); - }; - - // avatar database provider - - $app.data.isAvatarProviderDialogVisible = false; - - $app.methods.showAvatarProviderDialog = function () { - this.isAvatarProviderDialogVisible = true; - }; - - $app.methods.addAvatarProvider = function (url) { - if (!url) { - return; - } - this.showAvatarProviderDialog(); - if (!this.avatarRemoteDatabaseProviderList.includes(url)) { - this.avatarRemoteDatabaseProviderList.push(url); - } - this.saveAvatarProviderList(); - }; - - $app.methods.removeAvatarProvider = function (url) { - var length = this.avatarRemoteDatabaseProviderList.length; - for (var i = 0; i < length; ++i) { - if (this.avatarRemoteDatabaseProviderList[i] === url) { - this.avatarRemoteDatabaseProviderList.splice(i, 1); - } - } - this.saveAvatarProviderList(); - }; - - $app.methods.saveAvatarProviderList = async function () { - var length = this.avatarRemoteDatabaseProviderList.length; - for (var i = 0; i < length; ++i) { - if (!this.avatarRemoteDatabaseProviderList[i]) { - this.avatarRemoteDatabaseProviderList.splice(i, 1); - } - } - await configRepository.setString( - 'VRCX_avatarRemoteDatabaseProviderList', - JSON.stringify(this.avatarRemoteDatabaseProviderList) - ); - if (this.avatarRemoteDatabaseProviderList.length > 0) { - this.avatarRemoteDatabaseProvider = - this.avatarRemoteDatabaseProviderList[0]; - this.avatarRemoteDatabase = true; - } else { - this.avatarRemoteDatabaseProvider = ''; - this.avatarRemoteDatabase = false; - } - await configRepository.setBool( - 'VRCX_avatarRemoteDatabase', - this.avatarRemoteDatabase - ); - }; - - $app.methods.setAvatarProvider = function (provider) { - this.avatarRemoteDatabaseProvider = provider; - }; - - // #endregion - // #region | App: bulk unfavorite - - $app.methods.bulkCopyFavoriteSelection = function (type) { - let idList = ''; - switch (type) { - case 'friend': - for (let ctx of this.favoriteFriends) { - if (ctx.$selected) { - idList += `${ctx.id}\n`; - } - } - this.friendImportDialogInput = idList; - this.showFriendImportDialog(); - break; - - case 'world': - for (let ctx of this.favoriteWorlds) { - if (ctx.$selected) { - idList += `${ctx.id}\n`; - } - } - this.worldImportDialogInput = idList; - this.showWorldImportDialog(); - break; - - case 'avatar': - for (let ctx of this.favoriteAvatars) { - if (ctx.$selected) { - idList += `${ctx.id}\n`; - } - } - this.avatarImportDialogInput = idList; - this.showAvatarImportDialog(); - break; - - default: - break; - } - console.log('Favorite selection\n', idList); - }; - - $app.methods.clearBulkFavoriteSelection = function () { - for (var ctx of this.favoriteFriends) { - ctx.$selected = false; - } - for (var ctx of this.favoriteWorlds) { - ctx.$selected = false; - } - for (var ctx of this.favoriteAvatars) { - ctx.$selected = false; - } - }; - - // #endregion - // #region | App: local world favorites - - $app.data.localWorldFavoriteGroups = []; - $app.data.localWorldFavoritesList = []; - $app.data.localWorldFavorites = {}; - - $app.methods.addLocalWorldFavorite = function (worldId, group) { - if (this.hasLocalWorldFavorite(worldId, group)) { - return; - } - var ref = API.cachedWorlds.get(worldId); - if (typeof ref === 'undefined') { - return; - } - if (!this.localWorldFavoritesList.includes(worldId)) { - this.localWorldFavoritesList.push(worldId); - } - if (!this.localWorldFavorites[group]) { - this.localWorldFavorites[group] = []; - } - if (!this.localWorldFavoriteGroups.includes(group)) { - this.localWorldFavoriteGroups.push(group); - } - this.localWorldFavorites[group].unshift(ref); - database.addWorldToCache(ref); - database.addWorldToFavorites(worldId, group); - if ( - this.favoriteDialog.visible && - this.favoriteDialog.objectId === worldId - ) { - this.updateFavoriteDialog(worldId); - } - if (this.worldDialog.visible && this.worldDialog.id === worldId) { - this.worldDialog.isFavorite = true; - } - - // update UI - this.sortLocalWorldFavorites(); - }; - - $app.methods.removeLocalWorldFavorite = function (worldId, group) { - var favoriteGroup = this.localWorldFavorites[group]; - for (var i = 0; i < favoriteGroup.length; ++i) { - if (favoriteGroup[i].id === worldId) { - favoriteGroup.splice(i, 1); - } - } - - // remove from cache if no longer in favorites - var worldInFavorites = false; - for (var i = 0; i < this.localWorldFavoriteGroups.length; ++i) { - var groupName = this.localWorldFavoriteGroups[i]; - if (!this.localWorldFavorites[groupName] || group === groupName) { - continue; - } - for ( - var j = 0; - j < this.localWorldFavorites[groupName].length; - ++j - ) { - var id = this.localWorldFavorites[groupName][j].id; - if (id === worldId) { - worldInFavorites = true; - break; - } - } - } - if (!worldInFavorites) { - $app.removeFromArray(this.localWorldFavoritesList, worldId); - database.removeWorldFromCache(worldId); - } - database.removeWorldFromFavorites(worldId, group); - if ( - this.favoriteDialog.visible && - this.favoriteDialog.objectId === worldId - ) { - this.updateFavoriteDialog(worldId); - } - if (this.worldDialog.visible && this.worldDialog.id === worldId) { - this.worldDialog.isFavorite = - API.cachedFavoritesByObjectId.has(worldId); - } - - // update UI - this.sortLocalWorldFavorites(); - }; - - $app.methods.getLocalWorldFavorites = async function () { - this.localWorldFavoriteGroups = []; - this.localWorldFavoritesList = []; - this.localWorldFavorites = {}; - var worldCache = await database.getWorldCache(); - for (var i = 0; i < worldCache.length; ++i) { - var ref = worldCache[i]; - if (!API.cachedWorlds.has(ref.id)) { - API.applyWorld(ref); - } - } - var favorites = await database.getWorldFavorites(); - for (var i = 0; i < favorites.length; ++i) { - var favorite = favorites[i]; - if (!this.localWorldFavoritesList.includes(favorite.worldId)) { - this.localWorldFavoritesList.push(favorite.worldId); - } - if (!this.localWorldFavorites[favorite.groupName]) { - this.localWorldFavorites[favorite.groupName] = []; - } - if (!this.localWorldFavoriteGroups.includes(favorite.groupName)) { - this.localWorldFavoriteGroups.push(favorite.groupName); - } - var ref = API.cachedWorlds.get(favorite.worldId); - if (typeof ref === 'undefined') { - ref = { - id: favorite.worldId - }; - } - this.localWorldFavorites[favorite.groupName].unshift(ref); - } - if (this.localWorldFavoriteGroups.length === 0) { - // default group - this.localWorldFavorites.Favorites = []; - this.localWorldFavoriteGroups.push('Favorites'); - } - this.sortLocalWorldFavorites(); - }; - - $app.methods.hasLocalWorldFavorite = function (worldId, group) { - var favoriteGroup = this.localWorldFavorites[group]; - if (!favoriteGroup) { - return false; - } - for (var i = 0; i < favoriteGroup.length; ++i) { - if (favoriteGroup[i].id === worldId) { - return true; - } - } - return false; - }; - - $app.methods.getLocalWorldFavoriteGroupLength = function (group) { - var favoriteGroup = this.localWorldFavorites[group]; - if (!favoriteGroup) { - return 0; - } - return favoriteGroup.length; - }; - - $app.methods.newLocalWorldFavoriteGroup = function (group) { - if (this.localWorldFavoriteGroups.includes(group)) { - $app.$message({ - message: $t('prompt.new_local_favorite_group.message.error', { - name: group - }), - type: 'error' - }); - return; - } - if (!this.localWorldFavorites[group]) { - this.localWorldFavorites[group] = []; - } - if (!this.localWorldFavoriteGroups.includes(group)) { - this.localWorldFavoriteGroups.push(group); - } - this.sortLocalWorldFavorites(); - }; - - $app.methods.renameLocalWorldFavoriteGroup = function (newName, group) { - if (this.localWorldFavoriteGroups.includes(newName)) { - $app.$message({ - message: $t( - 'prompt.local_favorite_group_rename.message.error', - { name: newName } - ), - type: 'error' - }); - return; - } - this.localWorldFavoriteGroups.push(newName); - this.localWorldFavorites[newName] = this.localWorldFavorites[group]; - - $app.removeFromArray(this.localWorldFavoriteGroups, group); - delete this.localWorldFavorites[group]; - database.renameWorldFavoriteGroup(newName, group); - this.sortLocalWorldFavorites(); - }; - - $app.methods.sortLocalWorldFavorites = function () { - this.localWorldFavoriteGroups.sort(); - if (!this.sortFavorites) { - for (var i = 0; i < this.localWorldFavoriteGroups.length; ++i) { - var group = this.localWorldFavoriteGroups[i]; - if (this.localWorldFavorites[group]) { - this.localWorldFavorites[group].sort($utils.compareByName); - } - } - } - }; - - $app.methods.deleteLocalWorldFavoriteGroup = function (group) { - // remove from cache if no longer in favorites - var worldIdRemoveList = new Set(); - var favoriteGroup = this.localWorldFavorites[group]; - for (var i = 0; i < favoriteGroup.length; ++i) { - worldIdRemoveList.add(favoriteGroup[i].id); - } - - $app.removeFromArray(this.localWorldFavoriteGroups, group); - delete this.localWorldFavorites[group]; - database.deleteWorldFavoriteGroup(group); - - for (var i = 0; i < this.localWorldFavoriteGroups.length; ++i) { - var groupName = this.localWorldFavoriteGroups[i]; - if (!this.localWorldFavorites[groupName]) { - continue; - } - for ( - var j = 0; - j < this.localWorldFavorites[groupName].length; - ++j - ) { - var worldId = this.localWorldFavorites[groupName][j].id; - if (worldIdRemoveList.has(worldId)) { - worldIdRemoveList.delete(worldId); - break; - } - } - } - - worldIdRemoveList.forEach((id) => { - $app.removeFromArray(this.localWorldFavoritesList, id); - database.removeWorldFromCache(id); - }); - }; - - API.$on('WORLD', function (args) { - if ($app.localWorldFavoritesList.includes(args.ref.id)) { - // update db cache - database.addWorldToCache(args.ref); - } - }); - - API.$on('LOGIN', function () { - $app.getLocalWorldFavorites(); - }); - - // #endregion - // #region | App: Local Avatar Favorites - - $app.data.localAvatarFavoriteGroups = []; - $app.data.localAvatarFavoritesList = []; - $app.data.localAvatarFavorites = {}; - - $app.methods.addLocalAvatarFavorite = function (avatarId, group) { - if (this.hasLocalAvatarFavorite(avatarId, group)) { - return; - } - var ref = API.cachedAvatars.get(avatarId); - if (typeof ref === 'undefined') { - return; - } - if (!this.localAvatarFavoritesList.includes(avatarId)) { - this.localAvatarFavoritesList.push(avatarId); - } - if (!this.localAvatarFavorites[group]) { - this.localAvatarFavorites[group] = []; - } - if (!this.localAvatarFavoriteGroups.includes(group)) { - this.localAvatarFavoriteGroups.push(group); - } - this.localAvatarFavorites[group].unshift(ref); - database.addAvatarToCache(ref); - database.addAvatarToFavorites(avatarId, group); - if ( - this.favoriteDialog.visible && - this.favoriteDialog.objectId === avatarId - ) { - this.updateFavoriteDialog(avatarId); - } - if (this.avatarDialog.visible && this.avatarDialog.id === avatarId) { - this.avatarDialog.isFavorite = true; - } - - // update UI - this.sortLocalAvatarFavorites(); - }; - - $app.methods.removeLocalAvatarFavorite = function (avatarId, group) { - var favoriteGroup = this.localAvatarFavorites[group]; - for (var i = 0; i < favoriteGroup.length; ++i) { - if (favoriteGroup[i].id === avatarId) { - favoriteGroup.splice(i, 1); - } - } - - // remove from cache if no longer in favorites - var avatarInFavorites = false; - for (var i = 0; i < this.localAvatarFavoriteGroups.length; ++i) { - var groupName = this.localAvatarFavoriteGroups[i]; - if (!this.localAvatarFavorites[groupName] || group === groupName) { - continue; - } - for ( - var j = 0; - j < this.localAvatarFavorites[groupName].length; - ++j - ) { - var id = this.localAvatarFavorites[groupName][j].id; - if (id === avatarId) { - avatarInFavorites = true; - break; - } - } - } - if (!avatarInFavorites) { - $app.removeFromArray(this.localAvatarFavoritesList, avatarId); - if (!this.avatarHistory.has(avatarId)) { - database.removeAvatarFromCache(avatarId); - } - } - database.removeAvatarFromFavorites(avatarId, group); - if ( - this.favoriteDialog.visible && - this.favoriteDialog.objectId === avatarId - ) { - this.updateFavoriteDialog(avatarId); - } - if (this.avatarDialog.visible && this.avatarDialog.id === avatarId) { - this.avatarDialog.isFavorite = - API.cachedFavoritesByObjectId.has(avatarId); - } - - // update UI - this.sortLocalAvatarFavorites(); - }; - - API.$on('AVATAR', function (args) { - if ($app.localAvatarFavoritesList.includes(args.ref.id)) { - for (var i = 0; i < $app.localAvatarFavoriteGroups.length; ++i) { - var groupName = $app.localAvatarFavoriteGroups[i]; - if (!$app.localAvatarFavorites[groupName]) { - continue; - } - for ( - var j = 0; - j < $app.localAvatarFavorites[groupName].length; - ++j - ) { - var ref = $app.localAvatarFavorites[groupName][j]; - if (ref.id === args.ref.id) { - $app.localAvatarFavorites[groupName][j] = args.ref; - } - } - } - - // update db cache - database.addAvatarToCache(args.ref); - } - }); - - API.$on('LOGIN', function () { - $app.localAvatarFavoriteGroups = []; - $app.localAvatarFavoritesList = []; - $app.localAvatarFavorites = {}; - workerTimers.setTimeout(() => $app.getLocalAvatarFavorites(), 100); - }); - - $app.methods.getLocalAvatarFavorites = async function () { - this.localAvatarFavoriteGroups = []; - this.localAvatarFavoritesList = []; - this.localAvatarFavorites = {}; - var avatarCache = await database.getAvatarCache(); - for (var i = 0; i < avatarCache.length; ++i) { - var ref = avatarCache[i]; - if (!API.cachedAvatars.has(ref.id)) { - API.applyAvatar(ref); - } - } - var favorites = await database.getAvatarFavorites(); - for (var i = 0; i < favorites.length; ++i) { - var favorite = favorites[i]; - if (!this.localAvatarFavoritesList.includes(favorite.avatarId)) { - this.localAvatarFavoritesList.push(favorite.avatarId); - } - if (!this.localAvatarFavorites[favorite.groupName]) { - this.localAvatarFavorites[favorite.groupName] = []; - } - if (!this.localAvatarFavoriteGroups.includes(favorite.groupName)) { - this.localAvatarFavoriteGroups.push(favorite.groupName); - } - var ref = API.cachedAvatars.get(favorite.avatarId); - if (typeof ref === 'undefined') { - ref = { - id: favorite.avatarId - }; - } - this.localAvatarFavorites[favorite.groupName].unshift(ref); - } - if (this.localAvatarFavoriteGroups.length === 0) { - // default group - this.localAvatarFavorites.Favorites = []; - this.localAvatarFavoriteGroups.push('Favorites'); - } - this.sortLocalAvatarFavorites(); - }; - - $app.methods.hasLocalAvatarFavorite = function (avatarId, group) { - var favoriteGroup = this.localAvatarFavorites[group]; - if (!favoriteGroup) { - return false; - } - for (var i = 0; i < favoriteGroup.length; ++i) { - if (favoriteGroup[i].id === avatarId) { - return true; - } - } - return false; - }; - - $app.methods.promptNewLocalAvatarFavoriteGroup = function () { - this.$prompt( - $t('prompt.new_local_favorite_group.description'), - $t('prompt.new_local_favorite_group.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.new_local_favorite_group.ok'), - cancelButtonText: $t('prompt.new_local_favorite_group.cancel'), - inputPattern: /\S+/, - inputErrorMessage: $t( - 'prompt.new_local_favorite_group.input_error' - ), - callback: (action, instance) => { - if (action === 'confirm' && instance.inputValue) { - this.newLocalAvatarFavoriteGroup(instance.inputValue); - } - } - } - ); - }; - - $app.methods.newLocalAvatarFavoriteGroup = function (group) { - if (this.localAvatarFavoriteGroups.includes(group)) { - $app.$message({ - message: $t('prompt.new_local_favorite_group.message.error', { - name: group - }), - type: 'error' - }); - return; - } - if (!this.localAvatarFavorites[group]) { - this.localAvatarFavorites[group] = []; - } - if (!this.localAvatarFavoriteGroups.includes(group)) { - this.localAvatarFavoriteGroups.push(group); - } - this.sortLocalAvatarFavorites(); - }; - - $app.methods.promptLocalAvatarFavoriteGroupRename = function (group) { - this.$prompt( - $t('prompt.local_favorite_group_rename.description'), - $t('prompt.local_favorite_group_rename.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t( - 'prompt.local_favorite_group_rename.save' - ), - cancelButtonText: $t( - 'prompt.local_favorite_group_rename.cancel' - ), - inputPattern: /\S+/, - inputErrorMessage: $t( - 'prompt.local_favorite_group_rename.input_error' - ), - inputValue: group, - callback: (action, instance) => { - if (action === 'confirm' && instance.inputValue) { - this.renameLocalAvatarFavoriteGroup( - instance.inputValue, - group - ); - } - } - } - ); - }; - - $app.methods.renameLocalAvatarFavoriteGroup = function (newName, group) { - if (this.localAvatarFavoriteGroups.includes(newName)) { - $app.$message({ - message: $t( - 'prompt.local_favorite_group_rename.message.error', - { name: newName } - ), - type: 'error' - }); - return; - } - this.localAvatarFavoriteGroups.push(newName); - this.localAvatarFavorites[newName] = this.localAvatarFavorites[group]; - - $app.removeFromArray(this.localAvatarFavoriteGroups, group); - delete this.localAvatarFavorites[group]; - database.renameAvatarFavoriteGroup(newName, group); - this.sortLocalAvatarFavorites(); - }; - - $app.methods.promptLocalAvatarFavoriteGroupDelete = function (group) { - this.$confirm(`Delete Group? ${group}`, 'Confirm', { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - callback: (action) => { - if (action === 'confirm') { - this.deleteLocalAvatarFavoriteGroup(group); - } - } - }); - }; - - $app.methods.sortLocalAvatarFavorites = function () { - this.localAvatarFavoriteGroups.sort(); - if (!this.sortFavorites) { - for (var i = 0; i < this.localAvatarFavoriteGroups.length; ++i) { - var group = this.localAvatarFavoriteGroups[i]; - if (this.localAvatarFavorites[group]) { - this.localAvatarFavorites[group].sort($utils.compareByName); - } - } - } - }; - - $app.methods.deleteLocalAvatarFavoriteGroup = function (group) { - // remove from cache if no longer in favorites - var avatarIdRemoveList = new Set(); - var favoriteGroup = this.localAvatarFavorites[group]; - for (var i = 0; i < favoriteGroup.length; ++i) { - avatarIdRemoveList.add(favoriteGroup[i].id); - } - - $app.removeFromArray(this.localAvatarFavoriteGroups, group); - delete this.localAvatarFavorites[group]; - database.deleteAvatarFavoriteGroup(group); - - for (var i = 0; i < this.localAvatarFavoriteGroups.length; ++i) { - var groupName = this.localAvatarFavoriteGroups[i]; - if (!this.localAvatarFavorites[groupName]) { - continue; - } - for ( - var j = 0; - j < this.localAvatarFavorites[groupName].length; - ++j - ) { - var avatarId = this.localAvatarFavorites[groupName][j].id; - if (avatarIdRemoveList.has(avatarId)) { - avatarIdRemoveList.delete(avatarId); - break; - } - } - } - - avatarIdRemoveList.forEach((id) => { - // remove from cache if no longer in favorites - var avatarInFavorites = false; - loop: for ( - var i = 0; - i < this.localAvatarFavoriteGroups.length; - ++i - ) { - var groupName = this.localAvatarFavoriteGroups[i]; - if ( - !this.localAvatarFavorites[groupName] || - group === groupName - ) { - continue loop; - } - for ( - var j = 0; - j < this.localAvatarFavorites[groupName].length; - ++j - ) { - var avatarId = this.localAvatarFavorites[groupName][j].id; - if (id === avatarId) { - avatarInFavorites = true; - break loop; - } - } - } - if (!avatarInFavorites) { - $app.removeFromArray(this.localAvatarFavoritesList, id); - if (!this.avatarHistory.has(id)) { - database.removeAvatarFromCache(id); - } - } - }); - }; - - // #endregion - // #region | Local Favorite Friends - - $app.data.localFavoriteFriends = new Set(); - $app.data.localFavoriteFriendsGroups = JSON.parse( - await configRepository.getString( - 'VRCX_localFavoriteFriendsGroups', - '[]' - ) - ); - $app.methods.updateLocalFavoriteFriends = function () { - this.localFavoriteFriends.clear(); - for (const ref of API.cachedFavorites.values()) { - if ( - !ref.$isDeleted && - ref.type === 'friend' && - (this.localFavoriteFriendsGroups.includes(ref.$groupKey) || - this.localFavoriteFriendsGroups.length === 0) - ) { - this.localFavoriteFriends.add(ref.favoriteId); - } - } - this.updateSidebarFriendsList(); - - configRepository.setString( - 'VRCX_localFavoriteFriendsGroups', - JSON.stringify(this.localFavoriteFriendsGroups) - ); - }; - - $app.methods.updateSidebarFriendsList = function () { - for (var ctx of this.friends.values()) { - var isVIP = this.localFavoriteFriends.has(ctx.id); - if (ctx.isVIP === isVIP) { - continue; - } - ctx.isVIP = isVIP; - if (ctx.state !== 'online') { - continue; - } - if (ctx.isVIP) { - $app.removeFromArray(this.onlineFriends_, ctx); - this.vipFriends_.push(ctx); - this.sortVIPFriends = true; - } else { - $app.removeFromArray(this.vipFriends_, ctx); - this.onlineFriends_.push(ctx); - this.sortOnlineFriends = true; - } - } - }; - - // #endregion - // #region | App: ChatBox Blacklist - - $app.methods.checkChatboxBlacklist = function (msg) { - for (var i = 0; i < this.chatboxBlacklist.length; ++i) { - if (msg.includes(this.chatboxBlacklist[i])) { - return true; - } - } - return false; - }; - - // #endregion - // #region | App: ChatBox User Blacklist - $app.data.chatboxUserBlacklist = new Map(); - if (await configRepository.getString('VRCX_chatboxUserBlacklist')) { - $app.data.chatboxUserBlacklist = new Map( - Object.entries( - JSON.parse( - await configRepository.getString( - 'VRCX_chatboxUserBlacklist' - ) - ) - ) - ); - } - - $app.methods.getLocalAvatarFavoriteGroupLength = function (group) { - var favoriteGroup = this.localAvatarFavorites[group]; - if (!favoriteGroup) { - return 0; - } - return favoriteGroup.length; - }; - - $app.methods.saveChatboxUserBlacklist = async function () { - await configRepository.setString( - 'VRCX_chatboxUserBlacklist', - JSON.stringify(Object.fromEntries(this.chatboxUserBlacklist)) - ); - }; - - // #endregion - // #region | App: Instance queuing - - API.queuedInstances = new Map(); - - $app.methods.removeAllQueuedInstances = function () { - API.queuedInstances.forEach((ref) => { - this.$message({ - message: `Removed instance ${ref.$worldName} from queue`, - type: 'info' - }); - ref.$msgBox?.close(); - }); - API.queuedInstances.clear(); - }; - - $app.methods.removeQueuedInstance = function (instanceId) { - var ref = API.queuedInstances.get(instanceId); - if (typeof ref !== 'undefined') { - ref.$msgBox.close(); - API.queuedInstances.delete(instanceId); - } - }; - - API.applyQueuedInstance = function (instanceId) { - API.queuedInstances.forEach((ref) => { - if (ref.location !== instanceId) { - $app.$message({ - message: $t('message.instance.removed_form_queue', { - worldName: ref.$worldName - }), - type: 'info' - }); - ref.$msgBox?.close(); - API.queuedInstances.delete(ref.location); - } - }); - if (!instanceId) { - return; - } - if (!API.queuedInstances.has(instanceId)) { - var L = parseLocation(instanceId); - if (L.isRealInstance) { - instanceRequest - .getInstance({ - worldId: L.worldId, - instanceId: L.instanceId - }) - .then((args) => { - if (args.json?.queueSize) { - $app.instanceQueueUpdate( - instanceId, - args.json?.queueSize, - args.json?.queueSize - ); - } - }); - } - $app.instanceQueueUpdate(instanceId, 0, 0); - } - }; - - $app.methods.instanceQueueReady = function (instanceId) { - var ref = API.queuedInstances.get(instanceId); - if (typeof ref !== 'undefined') { - ref.$msgBox.close(); - API.queuedInstances.delete(instanceId); - } - var L = parseLocation(instanceId); - var group = API.cachedGroups.get(L.groupId); - var groupName = group?.name ?? ''; - var worldName = ref?.$worldName ?? ''; - const location = displayLocation(instanceId, worldName, groupName); - this.$message({ - message: `Instance ready to join ${location}`, - type: 'success' - }); - var noty = { - created_at: new Date().toJSON(), - type: 'group.queueReady', - imageUrl: group?.iconUrl, - message: `Instance ready to join ${location}`, - location: instanceId, - groupName, - worldName - }; - if ( - this.notificationTable.filters[0].value.length === 0 || - this.notificationTable.filters[0].value.includes(noty.type) - ) { - this.notifyMenu('notification'); - } - this.queueNotificationNoty(noty); - this.notificationTable.data.push(noty); - this.updateSharedFeed(true); - }; - - $app.methods.instanceQueueUpdate = async function ( - instanceId, - position, - queueSize - ) { - var ref = API.queuedInstances.get(instanceId); - if (typeof ref === 'undefined') { - ref = { - $msgBox: null, - $groupName: '', - $worldName: '', - location: instanceId, - position: 0, - queueSize: 0, - updatedAt: 0 - }; - } - ref.position = position; - ref.queueSize = queueSize; - ref.updatedAt = Date.now(); - if (!ref.$msgBox || ref.$msgBox.closed) { - ref.$msgBox = this.$message({ - message: '', - type: 'info', - duration: 0, - showClose: true, - customClass: 'vrc-instance-queue-message' - }); - } - if (!ref.$groupName) { - ref.$groupName = await this.getGroupName(instanceId); - } - if (!ref.$worldName) { - ref.$worldName = await this.getWorldName(instanceId); - } - const location = displayLocation( - instanceId, - ref.$worldName, - ref.$groupName - ); - ref.$msgBox.message = `You are in position ${ref.position} of ${ref.queueSize} in the queue for ${location} `; - API.queuedInstances.set(instanceId, ref); - // workerTimers.setTimeout(this.instanceQueueTimeout, 3600000); - }; - - $app.methods.instanceQueueClear = function () { - // remove all instances from queue - API.queuedInstances.forEach((ref) => { - ref.$msgBox.close(); - API.queuedInstances.delete(ref.location); - }); - }; - - // #endregion - - $app.methods.checkVRChatDebugLogging = async function () { - if (this.gameLogDisabled) { - return; - } - try { - var loggingEnabled = - await this.getVRChatRegistryKey('LOGGING_ENABLED'); - if ( - loggingEnabled === null || - typeof loggingEnabled === 'undefined' - ) { - // key not found - return; - } - if (parseInt(loggingEnabled, 10) === 1) { - // already enabled - return; - } - var result = await AppApi.SetVRChatRegistryKey( - 'LOGGING_ENABLED', - '1', - 4 - ); - if (!result) { - // failed to set key - this.$alert( - 'VRCX has noticed VRChat debug logging is disabled. VRCX requires debug logging in order to function correctly. Please enable debug logging in VRChat quick menu settings > debug > enable debug logging, then rejoin the instance or restart VRChat.', - 'Enable debug logging' - ); - console.error('Failed to enable debug logging', result); - return; - } - this.$alert( - 'VRCX has noticed VRChat debug logging is disabled and automatically re-enabled it. VRCX requires debug logging in order to function correctly.', - 'Enabled debug logging' - ); - console.log('Enabled debug logging'); - } catch (e) { - console.error(e); - } - }; - - // #endregion - // #region | App: Language - - $app.data.userDialogWorldSortingOptions = {}; - $app.data.userDialogWorldOrderOptions = {}; - - $app.methods.applyUserDialogSortingStrings = function () { - this.userDialogWorldSortingOptions = { - name: { - name: $t('dialog.user.worlds.sorting.name'), - value: 'name' - }, - updated: { - name: $t('dialog.user.worlds.sorting.updated'), - value: 'updated' - }, - created: { - name: $t('dialog.user.worlds.sorting.created'), - value: 'created' - }, - favorites: { - name: $t('dialog.user.worlds.sorting.favorites'), - value: 'favorites' - }, - popularity: { - name: $t('dialog.user.worlds.sorting.popularity'), - value: 'popularity' - } - }; - - this.userDialogWorldOrderOptions = { - descending: { - name: $t('dialog.user.worlds.order.descending'), - value: 'descending' - }, - ascending: { - name: $t('dialog.user.worlds.order.ascending'), - value: 'ascending' - } - }; - }; - - $app.data.groupDialogSortingOptions = {}; - $app.data.groupDialogFilterOptions = {}; - - $app.methods.applyGroupDialogSortingStrings = function () { - this.groupDialogSortingOptions = { - joinedAtDesc: { - name: $t('dialog.group.members.sorting.joined_at_desc'), - value: 'joinedAt:desc' - }, - joinedAtAsc: { - name: $t('dialog.group.members.sorting.joined_at_asc'), - value: 'joinedAt:asc' - }, - userId: { - name: $t('dialog.group.members.sorting.user_id'), - value: '' - } - }; - - this.groupDialogFilterOptions = { - everyone: { - name: $t('dialog.group.members.filters.everyone'), - id: null - }, - usersWithNoRole: { - name: $t('dialog.group.members.filters.users_with_no_role'), - id: '' - } - }; - }; - - $app.methods.applyLanguageStrings = function () { - // repply sorting strings - this.applyUserDialogSortingStrings(); - this.applyGroupDialogSortingStrings(); - this.userDialog.worldSorting = - this.userDialogWorldSortingOptions.updated; - this.userDialog.worldOrder = - this.userDialogWorldOrderOptions.descending; - this.userDialog.groupSorting = - userDialogGroupSortingOptions.alphabetical; - - this.groupDialog.memberFilter = this.groupDialogFilterOptions.everyone; - this.groupDialog.memberSortOrder = - this.groupDialogSortingOptions.joinedAtDesc; - }; - - $app.data.appLanguage = - (await configRepository.getString('VRCX_appLanguage')) ?? 'en'; - $utils.changeCJKorder($app.data.appLanguage); - i18n.locale = $app.data.appLanguage; - $app.methods.initLanguage = async function () { - if (!(await configRepository.getString('VRCX_appLanguage'))) { - var result = await AppApi.CurrentLanguage(); - if (!result) { - console.error('Failed to get current language'); - this.changeAppLanguage('en'); - return; - } - var lang = result.split('-')[0]; - i18n.availableLocales.forEach((ref) => { - var refLang = ref.split('_')[0]; - if (refLang === lang) { - this.changeAppLanguage(ref); - } - }); - } - - $app.applyLanguageStrings(); - }; - - $app.methods.changeAppLanguage = function (language) { - console.log('Language changed:', language); - this.appLanguage = language; - $utils.changeCJKorder(language); - i18n.locale = language; - configRepository.setString('VRCX_appLanguage', language); - this.applyLanguageStrings(); - this.updateVRConfigVars(); - this._stringComparer = undefined; - }; - - // #endregion - // #region | App: Random unsorted app methods, data structs, API functions, and an API feedback/file analysis event - - $app.data.changeLogDialog = { - visible: false, - buildName: '', - changeLog: '' - }; - - $app.methods.showChangeLogDialog = function () { - this.changeLogDialog.visible = true; - this.checkForVRCXUpdate(); - }; - - $app.methods.changeLogRemoveLinks = function (text) { - return text.replace(/([^!])\[[^\]]+\]\([^)]+\)/g, '$1'); - }; - - $app.methods.openFolderGeneric = function (path) { - AppApi.OpenFolderAndSelectItem(path, true); - }; - - // #endregion - // #region | Dialog: fullscreen image - - $app.data.fullscreenImageDialog = { - visible: false, - imageUrl: '', - fileName: '' - }; - - $app.methods.showFullscreenImageDialog = function (imageUrl, fileName) { - if (!imageUrl) { - return; - } - const D = this.fullscreenImageDialog; - D.imageUrl = imageUrl; - D.fileName = fileName; - D.visible = true; - }; - - // #endregion - // #region | Open common folders - - $app.methods.openVrcxAppDataFolder = function () { - AppApi.OpenVrcxAppDataFolder().then((result) => { - if (result) { - this.$message({ - message: 'Folder opened', - type: 'success' - }); - } else { - this.$message({ - message: "Folder dosn't exist", - type: 'error' - }); - } - }); - }; - - $app.methods.openVrcAppDataFolder = function () { - AppApi.OpenVrcAppDataFolder().then((result) => { - if (result) { - this.$message({ - message: 'Folder opened', - type: 'success' - }); - } else { - this.$message({ - message: "Folder dosn't exist", - type: 'error' - }); - } - }); - }; - - $app.methods.openVrcPhotosFolder = function () { - AppApi.OpenVrcPhotosFolder().then((result) => { - if (result) { - this.$message({ - message: 'Folder opened', - type: 'success' - }); - } else { - this.$message({ - message: "Folder dosn't exist", - type: 'error' - }); - } - }); - }; - - $app.methods.openVrcScreenshotsFolder = function () { - AppApi.OpenVrcScreenshotsFolder().then((result) => { - if (result) { - this.$message({ - message: 'Folder opened', - type: 'success' - }); - } else { - this.$message({ - message: "Folder dosn't exist", - type: 'error' - }); - } - }); - }; - - $app.methods.openCrashVrcCrashDumps = function () { - AppApi.OpenCrashVrcCrashDumps().then((result) => { - if (result) { - this.$message({ - message: 'Folder opened', - type: 'success' - }); - } else { - this.$message({ - message: "Folder dosn't exist", - type: 'error' - }); - } - }); - }; - - // #endregion - // #region | Close instance - - $app.methods.closeInstance = function (location) { - this.$confirm( - 'Continue? Close Instance, nobody will be able to join', - 'Confirm', - { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'warning', - callback: (action) => { - if (action !== 'confirm') { - return; - } - miscRequest.closeInstance({ location, hardClose: false }); - } - } - ); - }; - - API.$on('INSTANCE:CLOSE', function (args) { - if (args.json) { - $app.$message({ - message: $t('message.instance.closed'), - type: 'success' - }); - - this.$emit('INSTANCE', { - json: args.json - }); - } - }); - - // #endregion - // #region | Settings: Zoom - - $app.data.zoomLevel = ((await AppApi.GetZoom()) + 10) * 10; - - $app.methods.getZoomLevel = async function () { - this.zoomLevel = ((await AppApi.GetZoom()) + 10) * 10; - }; - - $app.methods.setZoomLevel = function () { - AppApi.SetZoom(this.zoomLevel / 10 - 10); - }; - - // #endregion - - // #region instance join history - - $app.data.instanceJoinHistory = new Map(); - - API.$on('LOGIN', function () { - $app.instanceJoinHistory = new Map(); - $app.getInstanceJoinHistory(); - }); - - $app.methods.getInstanceJoinHistory = async function () { - this.instanceJoinHistory = await database.getInstanceJoinHistory(); - }; - - $app.methods.addInstanceJoinHistory = function (location, dateTime) { - if (!location || !dateTime) { - return; - } - - if (this.instanceJoinHistory.has(location)) { - this.instanceJoinHistory.delete(location); - } - - var epoch = new Date(dateTime).getTime(); - this.instanceJoinHistory.set(location, epoch); - }; - - // #endregion - - // #region persistent data - - API.$on('WORLD:PERSIST:HAS', function (args) { - if ( - args.params.worldId === $app.worldDialog.id && - $app.worldDialog.visible - ) { - $app.worldDialog.hasPersistData = args.json !== false; - } - }); - - API.$on('WORLD:PERSIST:DELETE', function (args) { - if ( - args.params.worldId === $app.worldDialog.id && - $app.worldDialog.visible - ) { - $app.worldDialog.hasPersistData = false; - } - }); - - // #endregion - - $app.data.ossDialog = false; - - $app.computed.isLinux = function () { - return LINUX; - }; - - // friendsListSidebar - - // - DivideByFriendGroup - - $app.data.isSidebarDivideByFriendGroup = await configRepository.getBool( - 'VRCX_sidebarDivideByFriendGroup', - true - ); - - $app.methods.handleSwitchDivideByFriendGroup = async function () { - this.isSidebarDivideByFriendGroup = !this.isSidebarDivideByFriendGroup; - await configRepository.setBool( - 'VRCX_sidebarDivideByFriendGroup', - this.isSidebarDivideByFriendGroup - ); - }; - - // - SidebarGroupByInstance - - $app.data.isSidebarGroupByInstance = await configRepository.getBool( - 'VRCX_sidebarGroupByInstance', - true - ); - - $app.methods.toggleGroupByInstance = function () { - this.isSidebarGroupByInstance = !this.isSidebarGroupByInstance; - configRepository.setBool( - 'VRCX_sidebarGroupByInstance', - this.isSidebarGroupByInstance - ); - }; - - $app.data.isHideFriendsInSameInstance = await configRepository.getBool( - 'VRCX_hideFriendsInSameInstance', - false - ); - - $app.methods.toggleHideFriendsInSameInstance = function () { - this.isHideFriendsInSameInstance = !this.isHideFriendsInSameInstance; - configRepository.setBool( - 'VRCX_hideFriendsInSameInstance', - this.isHideFriendsInSameInstance - ); - }; - - // #endregion - // #region | Tab Props - - $app.computed.moderationTabBind = function () { - return { - menuActiveIndex: this.menuActiveIndex, - tableData: this.playerModerationTable, - shiftHeld: this.shiftHeld, - hideTooltips: this.hideTooltips - }; - }; - - $app.computed.friendsListTabBind = function () { - return { - menuActiveIndex: this.menuActiveIndex, - friends: this.friends, - hideTooltips: this.hideTooltips, - randomUserColours: this.randomUserColours, - sortStatus: this.sortStatus, - confirmDeleteFriend: this.confirmDeleteFriend, - friendsListSearch: this.friendsListSearch, - stringComparer: this.stringComparer - }; - }; - $app.computed.friendsListTabEvent = function () { - return { - 'get-all-user-stats': this.getAllUserStats, - 'lookup-user': this.lookupUser, - 'update:friends-list-search': (value) => - (this.friendsListSearch = value) - }; - }; - - $app.computed.sideBarTabBind = function () { - return { - isSideBarTabShow: this.isSideBarTabShow, - style: { width: `${this.asideWidth}px` }, - vipFriends: this.vipFriends, - onlineFriends: this.onlineFriends, - quickSearchRemoteMethod: this.quickSearchRemoteMethod, - quickSearchItems: this.quickSearchItems, - hideTooltips: this.hideTooltips, - onlineFriendCount: this.onlineFriendCount, - friends: this.friends, - isGameRunning: this.isGameRunning, - isSidebarDivideByFriendGroup: this.isSidebarDivideByFriendGroup, - isSidebarGroupByInstance: this.isSidebarGroupByInstance, - isHideFriendsInSameInstance: this.isHideFriendsInSameInstance, - gameLogDisabled: this.gameLogDisabled, - lastLocation: this.lastLocation, - lastLocationDestination: this.lastLocationDestination, - hideNicknames: this.hideNicknames, - activeFriends: this.activeFriends, - offlineFriends: this.offlineFriends, - groupInstances: this.groupInstances, - inGameGroupOrder: this.inGameGroupOrder, - groupedByGroupKeyFavoriteFriends: - this.groupedByGroupKeyFavoriteFriends, - isAgeGatedInstancesVisible: this.isAgeGatedInstancesVisible - }; - }; - - $app.computed.sideBarTabEvent = function () { - return { - 'show-group-dialog': this.showGroupDialog, - 'quick-search-change': this.quickSearchChange, - 'direct-access-paste': this.directAccessPaste, - 'refresh-friends-list': this.refreshFriendsList, - 'confirm-delete-friend': this.confirmDeleteFriend - }; - }; - - $app.computed.isSideBarTabShow = function () { - return !( - this.menuActiveIndex === 'friendList' || - this.menuActiveIndex === 'charts' - ); - }; - - $app.computed.favoritesTabBind = function () { - return { - menuActiveIndex: this.menuActiveIndex, - hideTooltips: this.hideTooltips, - shiftHeld: this.shiftHeld, - favoriteFriends: this.favoriteFriends, - sortFavorites: this.sortFavorites, - groupedByGroupKeyFavoriteFriends: - this.groupedByGroupKeyFavoriteFriends, - favoriteWorlds: this.favoriteWorlds, - localWorldFavoriteGroups: this.localWorldFavoriteGroups, - localWorldFavorites: this.localWorldFavorites, - avatarHistoryArray: this.avatarHistoryArray, - localAvatarFavoriteGroups: this.localAvatarFavoriteGroups, - localAvatarFavorites: this.localAvatarFavorites, - favoriteAvatars: this.favoriteAvatars, - localAvatarFavoritesList: this.localAvatarFavoritesList, - localWorldFavoritesList: this.localWorldFavoritesList - }; - }; - - $app.computed.favoritesTabEvent = function () { - return { - 'update:sort-favorites': (value) => (this.sortFavorites = value), - 'clear-bulk-favorite-selection': this.clearBulkFavoriteSelection, - 'bulk-copy-favorite-selection': this.bulkCopyFavoriteSelection, - 'get-local-world-favorites': this.getLocalWorldFavorites, - 'show-friend-import-dialog': this.showFriendImportDialog, - 'save-sort-favorites-option': this.saveSortFavoritesOption, - 'show-world-import-dialog': this.showWorldImportDialog, - 'show-world-dialog': this.showWorldDialog, - 'new-instance-self-invite': this.newInstanceSelfInvite, - 'delete-local-world-favorite-group': - this.deleteLocalWorldFavoriteGroup, - 'remove-local-world-favorite': this.removeLocalWorldFavorite, - 'show-avatar-import-dialog': this.showAvatarImportDialog, - 'show-avatar-dialog': this.showAvatarDialog, - 'remove-local-avatar-favorite': this.removeLocalAvatarFavorite, - 'select-avatar-with-confirmation': - this.selectAvatarWithConfirmation, - 'prompt-clear-avatar-history': this.promptClearAvatarHistory, - 'prompt-new-local-avatar-favorite-group': - this.promptNewLocalAvatarFavoriteGroup, - 'prompt-local-avatar-favorite-group-rename': - this.promptLocalAvatarFavoriteGroupRename, - 'prompt-local-avatar-favorite-group-delete': - this.promptLocalAvatarFavoriteGroupDelete, - 'new-local-world-favorite-group': this.newLocalWorldFavoriteGroup, - 'rename-local-world-favorite-group': - this.renameLocalWorldFavoriteGroup - }; - }; - - $app.computed.chartsTabBind = function () { - return { - getWorldName: this.getWorldName, - isDarkMode: this.isDarkMode, - dtHour12: this.dtHour12, - friendsMap: this.friends, - localFavoriteFriends: this.localFavoriteFriends - }; - }; - $app.computed.chartsTabEvent = function () { - return { - 'open-previous-instance-info-dialog': - this.showPreviousInstancesInfoDialog - }; - }; - - $app.computed.friendLogTabBind = function () { - return { - menuActiveIndex: this.menuActiveIndex, - friendLogTable: this.friendLogTable, - shiftHeld: this.shiftHeld - }; - }; - - $app.computed.gameLogTabBind = function () { - return { - menuActiveIndex: this.menuActiveIndex, - gameLogTable: this.gameLogTable, - shiftHeld: this.shiftHeld, - hideTooltips: this.hideTooltips, - gameLogIsFriend: this.gameLogIsFriend, - gameLogIsFavorite: this.gameLogIsFavorite - }; - }; - - $app.computed.gameLogTabEvent = function () { - return { - gameLogTableLookup: this.gameLogTableLookup, - lookupUser: this.lookupUser, - updateGameLogSessionTable: (val) => - (this.gameLogSessionTable = val), - updateSharedFeed: this.updateSharedFeed - }; - }; - - $app.computed.notificationTabBind = function () { - return { - menuActiveIndex: this.menuActiveIndex, - notificationTable: this.notificationTable, - shiftHeld: this.shiftHeld, - hideTooltips: this.hideTooltips, - lastLocation: this.lastLocation, - lastLocationDestination: this.lastLocationDestination, - isGameRunning: this.isGameRunning, - inviteResponseMessageTable: this.inviteResponseMessageTable, - uploadImage: this.uploadImage, - checkCanInvite: this.checkCanInvite, - inviteRequestResponseMessageTable: - this.inviteRequestResponseMessageTable - }; - }; - - $app.computed.notificationTabEvent = function () { - return { - inviteImageUpload: this.inviteImageUpload, - clearInviteImageUpload: this.clearInviteImageUpload - }; - }; - - $app.computed.feedTabBind = function () { - return { - menuActiveIndex: this.menuActiveIndex, - hideTooltips: this.hideTooltips, - feedTable: this.feedTable - }; - }; - - $app.computed.feedTabEvent = function () { - return { - feedTableLookup: this.feedTableLookup - }; - }; - - $app.computed.searchTabBind = function () { - return { - menuActiveIndex: this.menuActiveIndex, - searchText: this.searchText, - searchUserResults: this.searchUserResults, - randomUserColours: this.randomUserColours, - avatarRemoteDatabaseProviderList: - this.avatarRemoteDatabaseProviderList, - avatarRemoteDatabaseProvider: this.avatarRemoteDatabaseProvider, - hideTooltips: this.hideTooltips, - userDialog: this.userDialog, - lookupAvatars: this.lookupAvatars, - avatarRemoteDatabase: this.avatarRemoteDatabase - }; - }; - - $app.computed.searchTabEvent = function () { - return { - clearSearch: this.clearSearch, - setAvatarProvider: this.setAvatarProvider, - refreshUserDialogAvatars: this.refreshUserDialogAvatars, - moreSearchUser: this.moreSearchUser, - 'update:searchText': (value) => (this.searchText = value) - }; - }; - - $app.computed.profileTabBind = function () { - return { - menuActiveIndex: this.menuActiveIndex, - hideTooltips: this.hideTooltips, - inviteMessageTable: this.inviteMessageTable, - inviteResponseMessageTable: this.inviteResponseMessageTable, - inviteRequestMessageTable: this.inviteRequestMessageTable, - inviteRequestResponseMessageTable: - this.inviteRequestResponseMessageTable, - pastDisplayNameTable: this.pastDisplayNameTable, - friends: this.friends, - directAccessWorld: this.directAccessWorld, - parseUserUrl: this.parseUserUrl - }; - }; - - $app.computed.profileTabEvent = function () { - return { - logout: this.logout, - lookupUser: this.lookupUser, - showEditInviteMessageDialog: this.showEditInviteMessageDialog - }; - }; - - $app.computed.playerListTabBind = function () { - return { - menuActiveIndex: this.menuActiveIndex, - currentInstanceWorld: this.currentInstanceWorld, - currentInstanceLocation: this.currentInstanceLocation, - currentInstanceWorldDescriptionExpanded: - this.currentInstanceWorldDescriptionExpanded, - photonLoggingEnabled: this.photonLoggingEnabled, - photonEventTableTypeFilter: this.photonEventTableTypeFilter, - photonEventTableTypeFilterList: this.photonEventTableTypeFilterList, - photonEventTableFilter: this.photonEventTableFilter, - hideTooltips: this.hideTooltips, - ipcEnabled: this.ipcEnabled, - photonEventIcon: this.photonEventIcon, - photonEventTable: this.photonEventTable, - photonEventTablePrevious: this.photonEventTablePrevious, - currentInstanceUserList: this.currentInstanceUserList, - chatboxUserBlacklist: this.chatboxUserBlacklist, - randomUserColours: this.randomUserColours, - lastLocation: this.lastLocation - }; - }; - - $app.computed.playerListTabEvent = function () { - return { - photonEventTableFilterChange: this.photonEventTableFilterChange, - getCurrentInstanceUserList: this.getCurrentInstanceUserList, - showUserFromPhotonId: this.showUserFromPhotonId, - lookupUser: this.lookupUser - }; - }; - - $app.computed.loginPageBind = function () { - return { - hideTooltips: this.hideTooltips, - loginForm: this.loginForm, - enableCustomEndpoint: this.enableCustomEndpoint - }; - }; - - $app.computed.loginPageEvent = function () { - return { - showVRCXUpdateDialog: this.showVRCXUpdateDialog, - promptProxySettings: this.promptProxySettings, - toggleCustomEndpoint: this.toggleCustomEndpoint, - deleteSavedLogin: this.deleteSavedLogin, - login: this.login, - relogin: this.relogin - }; - }; - - $app.computed.vrcxUpdateDialogBind = function () { - return { - VRCXUpdateDialog: this.VRCXUpdateDialog, - appVersion: this.appVersion, - checkingForVRCXUpdate: this.checkingForVRCXUpdate, - updateInProgress: this.updateInProgress, - updateProgress: this.updateProgress, - updateProgressText: this.updateProgressText, - pendingVRCXInstall: this.pendingVRCXInstall, - branch: this.branch, - branches: this.branches - }; - }; - - $app.computed.vrcxUpdateDialogEvent = function () { - return { - 'update:branch': (value) => (this.branch = value), - loadBranchVersions: this.loadBranchVersions, - cancelUpdate: this.cancelUpdate, - installVRCXUpdate: this.installVRCXUpdate, - restartVRCX: this.restartVRCX - }; - }; - - $app.methods.languageClass = function (key) { - return languageClass(key); - }; - - // #endregion - // #region | Electron - - if (LINUX) { - window.electron.onWindowPositionChanged((event, position) => { - window.$app.locationX = position.x; - window.$app.locationY = position.y; - window.$app.saveVRCXWindowOption(); - }); - - window.electron.onWindowSizeChanged((event, size) => { - window.$app.sizeWidth = size.width; - window.$app.sizeHeight = size.height; - window.$app.saveVRCXWindowOption(); - }); - - window.electron.onWindowStateChange((event, state) => { - window.$app.windowState = state; - window.$app.saveVRCXWindowOption(); - }); - - // window.electron.onWindowClosed((event) => { - // window.$app.saveVRCXWindowOption(); - // }); - } - - // #endregion - - // "$app" is being replaced by Vue, update references inside all the classes - $app = new Vue($app); - window.$app = $app; - window.API = API; - window.$t = $t; - for (let value of Object.values(vrcxClasses)) { - value.updateRef($app); - } -})(); -// #endregion - -// // #endregion -// // #region | Dialog: templateDialog - -// $app.data.templateDialog = { -// visible: false, -// }; - -// $app.methods.showTemplateDialog = function () { -// this.$nextTick(() => $app.adjustDialogZ(this.$refs.templateDialog.$el)); -// var D = this.templateDialog; -// D.visible = true; -// }; - -// // #endregion +window.$app = $app; +export { $app }; diff --git a/src/app.pug b/src/app.pug index 542f803f..4e829c94 100644 --- a/src/app.pug +++ b/src/app.pug @@ -1,63 +1,71 @@ doctype html #x-app.x-app(@dragenter.prevent @dragover.prevent @drop.prevent) - LoginPage(v-if="!API.isLoggedIn" v-bind="loginPageBind" v-on="loginPageEvent") + //- ### Login ### + Login(v-if='!watchState.isLoggedIn') - VRCXUpdateDialog(v-bind="vrcxUpdateDialogBind" v-on="vrcxUpdateDialogEvent") + VRCXUpdateDialog - //- menu - .x-menu-container - //- download progress, update pending - .pending-update(v-if='updateInProgress' @click='showVRCXUpdateDialog') - el-progress( - type='circle' - width='50' - stroke-width='3' - :percentage='updateProgress' - :format='updateProgressText') - .pending-update(v-else-if='pendingVRCXUpdate || pendingVRCXInstall') - el-button( - type='default' - @click='showVRCXUpdateDialog' - size='mini' - icon='el-icon-download' - circle - style='font-size: 14px; height: 50px; width: 50px') + template(v-if='watchState.isLoggedIn') + //- ### Menu ### + NavMenu - NavMenu(ref='menu' @select='selectMenu' :menu-active-index='menuActiveIndex') + //- ### Sidebar ### + Sidebar - //- ### Tabs ### - template(v-if='API.isLoggedIn') - FeedTab(v-bind='feedTabBind' v-on='feedTabEvent') + //- ### Tabs ### + Feed - GameLogTab(v-bind='gameLogTabBind' v-on='gameLogTabEvent') + GameLog - PlayerListTab(v-bind='playerListTabBind' v-on='playerListTabEvent') + PlayerList - SearchTab(v-bind='searchTabBind' v-on='searchTabEvent') + Search - FavoritesTab(v-bind='favoritesTabBind' v-on='favoritesTabEvent') + Favorites - FriendLogTab(v-bind='friendLogTabBind') + FriendLog - ModerationTab(v-bind='moderationTabBind') + Moderation - NotificationTab(v-bind='notificationTabBind' v-on='notificationTabEvent') + Notification - ProfileTab(v-bind='profileTabBind' v-on='profileTabEvent') + FriendList - FriendListTab(v-bind='friendsListTabBind' v-on='friendsListTabEvent') + Charts - KeepAlive - ChartsTab(v-if='menuActiveIndex === "charts"' v-bind='chartsTabBind' v-on='chartsTabEvent') + Profile - //- settings - include ./mixins/tabs/settings.pug - +settingsTab - - SideBar(v-bind='sideBarTabBind' v-on='sideBarTabEvent') + Settings //- ## Dialogs ## -\\ - include ./mixins/dialogs/dialogs.pug - +dialogs + UserDialog - //- el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="templateDialog" :visible.sync="templateDialog.visible" :title="$t('dialog.template_dialog.header')" width="450px") + WorldDialog + + AvatarDialog + + GroupDialog + + GalleryDialog + + FullscreenImageDialog + + PreviousInstancesInfoDialog + + LaunchDialog + + LaunchOptionsDialog + + FriendImportDialog + + WorldImportDialog + + AvatarImportDialog + + ChooseFavoriteGroupDialog + + EditInviteMessageDialog + + VRChatConfigDialog + + PrimaryPasswordDialog diff --git a/src/app.scss b/src/app.scss index 3e021cb1..a580d427 100644 --- a/src/app.scss +++ b/src/app.scss @@ -8,6 +8,9 @@ // For a copy, see . // +@use "./assets/scss/flags.scss"; +@use "./assets/scss/animated-emoji.scss"; + @import '~animate.css/animate.min.css'; @import '~noty/lib/noty.css'; @import '~element-ui/lib/theme-chalk/index.css'; @@ -299,6 +302,7 @@ hr.x-vertical-divider { flex-direction: column; background: #f8f8f8; padding: 5px; + order: 99; } .el-popper.x-quick-search { diff --git a/src/assets/scss/themes/theme.darkvanillaold.scss b/src/assets/scss/themes/theme.darkvanillaold.scss index 5af7d6d8..71babb88 100644 --- a/src/assets/scss/themes/theme.darkvanillaold.scss +++ b/src/assets/scss/themes/theme.darkvanillaold.scss @@ -2,7 +2,7 @@ * VRCX Dark-Vanilla theme by MintLily * https://github.com/MintLily/Dark-Vanilla */ -@import 'theme.dark'; +@use 'theme.dark'; :root { --ThemeName: 'Dark Vanilla'; --ThemeVersion: 'v1.7'; diff --git a/src/assets/scss/themes/theme.material3.scss b/src/assets/scss/themes/theme.material3.scss index a8e4d83e..85b5429b 100644 --- a/src/assets/scss/themes/theme.material3.scss +++ b/src/assets/scss/themes/theme.material3.scss @@ -2,7 +2,7 @@ * VRCX Material-You-like theme by Kamiya * https://github.com/kamiya10/VRCX-theme */ -@import 'theme.dark'; +@use 'theme.dark'; @import url('https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;600&family=Noto+Sans+TC:wght@300;400;500&family=Noto+Sans+SC:wght@300;400;500&family=Noto+Sans+JP:wght@300;400;500&family=Roboto&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200'); @@ -653,6 +653,8 @@ input[type='number'], border-left: 1px solid rgb(var(--md-sys-color-surface-variant)); */ padding: 8px 10px; + display: flex; + align-items: center; } /* ---------- Switch ---------- */ @@ -1083,8 +1085,8 @@ input[type='number'], border-radius: 8px; height: 28px; padding: 0 12px; - margin-top: 8px !important; - margin-right: 8px !important; +// margin-top: 8px !important; +// margin-right: 8px !important; color: rgb(var(--md-sys-color-on-surface-variant)); font-family: var(--md-sys-typescale-label-large-font); line-height: 28px; @@ -1380,7 +1382,7 @@ img.x-link.el-popover__reference { *:not(.x-user-dialog, .x-world-dialog, .x-avatar-dialog, .x-group-dialog) > .el-dialog:not([aria-label*='Notification Position']):not( [aria-label*='Launch'] - ):not([aria-label*='VRCX Updater']) { + ):not([aria-label*='VRCX Updater']):not([aria-label*='Social Status']) { max-width: 1125px !important; width: 1125px !important; } @@ -2008,6 +2010,7 @@ i.x-user-status { .el-collapse-item .el-tag--mini { background-color: transparent; border: transparent; + padding-top: 6px; } .simple-switch { justify-content: space-between; @@ -2071,4 +2074,12 @@ i.x-user-status { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; +} +.el-dialog[aria-label='Launch'] .el-form .el-form-item__content { + display: flex; + align-items: center; +} +.el-dialog[aria-label='Launch'] .el-form > .el-form-item:nth-child(2) .el-form-item__label { + display: flex; + align-items: center; } \ No newline at end of file diff --git a/src/assets/scss/themes/theme.pink.scss b/src/assets/scss/themes/theme.pink.scss index 9f78ad57..f53f098a 100644 --- a/src/assets/scss/themes/theme.pink.scss +++ b/src/assets/scss/themes/theme.pink.scss @@ -2,7 +2,7 @@ * VRCX Pink theme by Kamiya * https://github.com/kamiya10/VRCX-theme */ -@import 'theme.dark'; +@use 'theme.dark'; @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap'); :root { --theme: #dfa2a2; @@ -70,7 +70,7 @@ textarea { .el-textarea .el-input__count, .el-textarea__inner, .x-menu-container { - background-color: var(--lighter-bg); + background-color: var(--lighter-bg) !important; } .el-color-picker__panel { border-color: var(--lighter-bg); diff --git a/src/bootstrap.js b/src/bootstrap.js new file mode 100644 index 00000000..f99f9ac1 --- /dev/null +++ b/src/bootstrap.js @@ -0,0 +1,76 @@ +import '@fontsource/noto-sans-kr'; +import '@fontsource/noto-sans-jp'; +import '@fontsource/noto-sans-sc'; +import '@fontsource/noto-sans-tc'; +import '@infolektuell/noto-color-emoji'; + +import Vue from 'vue'; +import { PiniaVuePlugin } from 'pinia'; +import { DataTables } from 'vue-data-tables'; +import VueLazyload from 'vue-lazyload'; +import configRepository from './service/config'; +import vrcxJsonStorage from './service/jsonStorage'; +import { + changeAppDarkStyle, + changeAppThemeStyle, + refreshCustomCss, + refreshCustomScript, + systemIsDarkMode +} from './shared/utils'; +import { i18n } from './plugin'; + +configRepository.init(); +i18n.locale = await configRepository.getString('VRCX_appLanguage', 'en'); + +AppApi.SetUserAgent(); + +const initThemeMode = await configRepository.getString( + 'VRCX_ThemeMode', + 'system' +); + +let isDarkMode; + +if (initThemeMode === 'light') { + isDarkMode = false; +} else if (initThemeMode === 'system') { + isDarkMode = systemIsDarkMode(); +} else { + isDarkMode = true; +} +changeAppDarkStyle(isDarkMode); +changeAppThemeStyle(initThemeMode); + +refreshCustomCss(); +refreshCustomScript(); + +Vue.use(PiniaVuePlugin); +Vue.use(DataTables); + +Vue.use(VueLazyload, { + preLoad: 1, + observer: true, + observerOptions: { + rootMargin: '0px', + threshold: 0 + }, + attempt: 3 +}); + +new vrcxJsonStorage(VRCXStorage); + +// some workaround for failing to get voice list first run +speechSynthesis.getVoices(); + +if (process.env.NODE_ENV !== 'production') { + Vue.config.errorHandler = function (err, vm, info) { + console.error('Vue Error:', err); + console.error('Component:', vm); + console.error('Error Info:', info); + }; + Vue.config.warnHandler = function (msg, vm, trace) { + console.warn('Vue Warning:', msg); + console.warn('Component:', vm); + console.warn('Trace:', trace); + }; +} diff --git a/src/classes/API/config.js b/src/classes/API/config.js deleted file mode 100644 index 5a86cacf..00000000 --- a/src/classes/API/config.js +++ /dev/null @@ -1,46 +0,0 @@ -import { baseClass, $app, API, $t, $utils } from '../baseClass.js'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - init() { - API.getConfig = function () { - return this.call('config', { - method: 'GET' - }).then((json) => { - var args = { - json - }; - this.$emit('CONFIG', args); - return args; - }); - }; - - API.$on('CONFIG', function (args) { - args.ref = this.applyConfig(args.json); - }); - - API.$on('CONFIG', function (args) { - if (typeof args.ref?.whiteListedAssetUrls !== 'object') { - console.error('Invalid config whiteListedAssetUrls'); - } - AppApi.PopulateImageHosts( - JSON.stringify(args.ref.whiteListedAssetUrls) - ); - }); - - API.applyConfig = function (json) { - var ref = { - ...json - }; - this.cachedConfig = ref; - return ref; - }; - } - - _data = {}; - - _methods = {}; -} diff --git a/src/classes/_classTemplate.js b/src/classes/_classTemplate.js deleted file mode 100644 index 2bf5ec36..00000000 --- a/src/classes/_classTemplate.js +++ /dev/null @@ -1,16 +0,0 @@ -import * as workerTimers from 'worker-timers'; -import configRepository from '../service/config.js'; -import database from '../service/database.js'; -import { baseClass, $app, API, $t, $utils } from './baseClass.js'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - init() {} - - _data = {}; - - _methods = {}; -} diff --git a/src/classes/apiInit.js b/src/classes/apiInit.js deleted file mode 100644 index 5fa48ca3..00000000 --- a/src/classes/apiInit.js +++ /dev/null @@ -1,53 +0,0 @@ -import { baseClass, $app, API, $t } from './baseClass.js'; - -export default class extends baseClass { - constructor(_app) { - super(_app); - } - - eventHandlers = new Map(); - - $emit = function (name, ...args) { - if ($app.debug) { - console.log(name, ...args); - } - var handlers = this.eventHandlers.get(name); - if (typeof handlers === 'undefined') { - return; - } - try { - for (var handler of handlers) { - handler.apply(this, args); - } - } catch (err) { - console.error(err); - } - }; - - $on = function (name, handler) { - var handlers = this.eventHandlers.get(name); - if (typeof handlers === 'undefined') { - handlers = []; - this.eventHandlers.set(name, handlers); - } - handlers.push(handler); - }; - - $off = function (name, handler) { - var handlers = this.eventHandlers.get(name); - if (typeof handlers === 'undefined') { - return; - } - var { length } = handlers; - for (var i = 0; i < length; ++i) { - if (handlers[i] === handler) { - if (length > 1) { - handlers.splice(i, 1); - } else { - this.eventHandlers.delete(name); - } - break; - } - } - }; -} diff --git a/src/classes/apiLogin.js b/src/classes/apiLogin.js deleted file mode 100644 index 7f224119..00000000 --- a/src/classes/apiLogin.js +++ /dev/null @@ -1,421 +0,0 @@ -import Noty from 'noty'; -import security from '../service/security.js'; -import configRepository from '../service/config.js'; -import { baseClass, $app, API, $t } from './baseClass.js'; -/* eslint-disable no-unused-vars */ -let webApiService = {}; -/* eslint-enable no-unused-vars */ - -export default class extends baseClass { - constructor(_app, _API, _t, _webApiService) { - super(_app, _API, _t); - webApiService = _webApiService; - } - - async init() { - API.isLoggedIn = false; - API.attemptingAutoLogin = false; - API.autoLoginAttempts = new Set(); - - /** - * @param {{ username: string, password: string }} params credential to login - * @returns {Promise<{origin: boolean, json: any, params}>} - */ - API.login = function (params) { - var { username, password, saveCredentials, cipher } = params; - username = encodeURIComponent(username); - password = encodeURIComponent(password); - var auth = btoa(`${username}:${password}`); - if (saveCredentials) { - delete params.saveCredentials; - if (cipher) { - params.password = cipher; - delete params.cipher; - } - $app.saveCredentials = params; - } - return this.call('auth/user', { - method: 'GET', - headers: { - Authorization: `Basic ${auth}` - } - }).then((json) => { - var args = { - json, - params, - origin: true - }; - if ( - json.requiresTwoFactorAuth && - json.requiresTwoFactorAuth.includes('emailOtp') - ) { - this.$emit('USER:EMAILOTP', args); - } else if (json.requiresTwoFactorAuth) { - this.$emit('USER:2FA', args); - } else { - this.$emit('USER:CURRENT', args); - } - return args; - }); - }; - - /** - * @param {{ code: string }} params One-time password - * @returns {Promise<{json: any, params}>} - */ - API.verifyOTP = function (params) { - return this.call('auth/twofactorauth/otp/verify', { - method: 'POST', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('OTP', args); - return args; - }); - }; - - /** - * @param {{ code: string }} params One-time token - * @returns {Promise<{json: any, params}>} - */ - API.verifyTOTP = function (params) { - return this.call('auth/twofactorauth/totp/verify', { - method: 'POST', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('TOTP', args); - return args; - }); - }; - - /** - * @param {{ code: string }} params One-time token - * @returns {Promise<{json: any, params}>} - */ - API.verifyEmailOTP = function (params) { - return this.call('auth/twofactorauth/emailotp/verify', { - method: 'POST', - params - }).then((json) => { - var args = { - json, - params - }; - this.$emit('EMAILOTP', args); - return args; - }); - }; - - API.$on('AUTOLOGIN', function () { - if (this.attemptingAutoLogin) { - return; - } - this.attemptingAutoLogin = true; - var user = - $app.loginForm.savedCredentials[ - $app.loginForm.lastUserLoggedIn - ]; - if (typeof user === 'undefined') { - this.attemptingAutoLogin = false; - return; - } - if ($app.enablePrimaryPassword) { - console.error( - 'Primary password is enabled, this disables auto login.' - ); - this.attemptingAutoLogin = false; - this.logout(); - return; - } - var attemptsInLastHour = Array.from(this.autoLoginAttempts).filter( - (timestamp) => timestamp > new Date().getTime() - 3600000 - ).length; - if (attemptsInLastHour >= 3) { - console.error( - 'More than 3 auto login attempts within the past hour, logging out instead of attempting auto login.' - ); - this.attemptingAutoLogin = false; - this.logout(); - return; - } - this.autoLoginAttempts.add(new Date().getTime()); - $app.relogin(user) - .then(() => { - if (this.errorNoty) { - this.errorNoty.close(); - } - this.errorNoty = new Noty({ - type: 'success', - text: 'Automatically logged in.' - }).show(); - console.log('Automatically logged in.'); - }) - .catch((err) => { - if (this.errorNoty) { - this.errorNoty.close(); - } - this.errorNoty = new Noty({ - type: 'error', - text: 'Failed to login automatically.' - }).show(); - console.error('Failed to login automatically.', err); - }) - .finally(() => { - if (!navigator.onLine) { - this.errorNoty = new Noty({ - type: 'error', - text: `You're offline.` - }).show(); - console.error(`You're offline.`); - } - }); - }); - - API.$on('USER:CURRENT', function () { - this.attemptingAutoLogin = false; - }); - - API.$on('LOGOUT', function () { - this.attemptingAutoLogin = false; - this.autoLoginAttempts.clear(); - }); - - API.logout = function () { - this.$emit('LOGOUT'); - // return this.call('logout', { - // method: 'PUT' - // }).finally(() => { - // this.$emit('LOGOUT'); - // }); - }; - } - - _data = { - loginForm: { - loading: true, - username: '', - password: '', - endpoint: '', - websocket: '', - saveCredentials: false, - savedCredentials: {}, - lastUserLoggedIn: '', - rules: { - username: [ - { - required: true, - trigger: 'blur' - } - ], - password: [ - { - required: true, - trigger: 'blur' - } - ] - } - } - }; - - _methods = { - async relogin(user) { - var { loginParmas } = user; - if (user.cookies) { - await webApiService.setCookies(user.cookies); - } - this.loginForm.lastUserLoggedIn = user.user.id; // for resend email 2fa - if (loginParmas.endpoint) { - API.endpointDomain = loginParmas.endpoint; - API.websocketDomain = loginParmas.websocket; - } else { - API.endpointDomain = API.endpointDomainVrchat; - API.websocketDomain = API.websocketDomainVrchat; - } - return new Promise((resolve, reject) => { - this.loginForm.loading = true; - if (this.enablePrimaryPassword) { - this.checkPrimaryPassword(loginParmas) - .then((pwd) => { - return API.getConfig() - .catch((err) => { - reject(err); - }) - .then(() => { - API.login({ - username: loginParmas.username, - password: pwd, - cipher: loginParmas.password, - endpoint: loginParmas.endpoint, - websocket: loginParmas.websocket - }) - .catch((err2) => { - // API.logout(); - reject(err2); - }) - .then(() => { - resolve(); - }); - }); - }) - .catch((_) => { - this.$message({ - message: 'Incorrect primary password', - type: 'error' - }); - reject(_); - }); - } else { - API.getConfig() - .catch((err) => { - reject(err); - }) - .then(() => { - API.login({ - username: loginParmas.username, - password: loginParmas.password, - endpoint: loginParmas.endpoint, - websocket: loginParmas.websocket - }) - .catch((err2) => { - API.logout(); - reject(err2); - }) - .then(() => { - resolve(); - }); - }); - } - }).finally(() => (this.loginForm.loading = false)); - }, - - async deleteSavedLogin(userId) { - var savedCredentials = JSON.parse( - await configRepository.getString('savedCredentials') - ); - delete savedCredentials[userId]; - // Disable primary password when no account is available. - if (Object.keys(savedCredentials).length === 0) { - this.enablePrimaryPassword = false; - await configRepository.setBool('enablePrimaryPassword', false); - } - this.loginForm.savedCredentials = savedCredentials; - var jsonCredentials = JSON.stringify(savedCredentials); - await configRepository.setString( - 'savedCredentials', - jsonCredentials - ); - new Noty({ - type: 'success', - text: 'Account removed.' - }).show(); - }, - - async login() { - await webApiService.clearCookies(); - if (!this.loginForm.loading) { - this.loginForm.loading = true; - if (this.loginForm.endpoint) { - API.endpointDomain = this.loginForm.endpoint; - API.websocketDomain = this.loginForm.websocket; - } else { - API.endpointDomain = API.endpointDomainVrchat; - API.websocketDomain = API.websocketDomainVrchat; - } - API.getConfig() - .catch((err) => { - this.loginForm.loading = false; - throw err; - }) - .then((args) => { - if ( - this.loginForm.saveCredentials && - this.enablePrimaryPassword - ) { - $app.$prompt( - $t('prompt.primary_password.description'), - $t('prompt.primary_password.header'), - { - inputType: 'password', - inputPattern: /[\s\S]{1,32}/ - } - ) - .then(({ value }) => { - let saveCredential = - this.loginForm.savedCredentials[ - Object.keys( - this.loginForm.savedCredentials - )[0] - ]; - security - .decrypt( - saveCredential.loginParmas.password, - value - ) - .then(() => { - security - .encrypt( - this.loginForm.password, - value - ) - .then((pwd) => { - API.login({ - username: - this.loginForm - .username, - password: - this.loginForm - .password, - endpoint: - this.loginForm - .endpoint, - websocket: - this.loginForm - .websocket, - saveCredentials: - this.loginForm - .saveCredentials, - cipher: pwd - }); - }); - }); - }) - .finally(() => { - this.loginForm.loading = false; - }); - return args; - } - API.login({ - username: this.loginForm.username, - password: this.loginForm.password, - endpoint: this.loginForm.endpoint, - websocket: this.loginForm.websocket, - saveCredentials: this.loginForm.saveCredentials - }).finally(() => { - this.loginForm.loading = false; - }); - return args; - }); - } - }, - - logout() { - this.$confirm('Continue? Logout', 'Confirm', { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - callback: (action) => { - if (action === 'confirm') { - API.logout(); - } - } - }); - } - }; -} diff --git a/src/classes/apiRequestHandler.js b/src/classes/apiRequestHandler.js deleted file mode 100644 index 64761c9e..00000000 --- a/src/classes/apiRequestHandler.js +++ /dev/null @@ -1,402 +0,0 @@ -import Noty from 'noty'; -import { baseClass, $app, API, $t } from './baseClass.js'; -/* eslint-disable no-unused-vars */ -let webApiService = {}; -/* eslint-enable no-unused-vars */ - -export default class extends baseClass { - constructor(_app, _API, _t, _webApiService) { - super(_app, _API, _t); - webApiService = _webApiService; - } - - init() { - API.cachedConfig = {}; - API.pendingGetRequests = new Map(); - API.failedGetRequests = new Map(); - API.endpointDomainVrchat = 'https://api.vrchat.cloud/api/1'; - API.websocketDomainVrchat = 'wss://pipeline.vrchat.cloud'; - API.endpointDomain = 'https://api.vrchat.cloud/api/1'; - API.websocketDomain = 'wss://pipeline.vrchat.cloud'; - - API.call = function (endpoint, options) { - var init = { - url: `${API.endpointDomain}/${endpoint}`, - method: 'GET', - ...options - }; - var { params } = init; - if (init.method === 'GET') { - // don't retry recent 404/403 - if (this.failedGetRequests.has(endpoint)) { - var lastRun = this.failedGetRequests.get(endpoint); - if (lastRun >= Date.now() - 900000) { - // 15mins - throw new Error( - `${$t('api.error.message.403_404_bailing_request')}, ${endpoint}` - ); - } - this.failedGetRequests.delete(endpoint); - } - // transform body to url - if (params === Object(params)) { - var url = new URL(init.url); - var { searchParams } = url; - for (var key in params) { - searchParams.set(key, params[key]); - } - init.url = url.toString(); - } - // merge requests - var req = this.pendingGetRequests.get(init.url); - if (typeof req !== 'undefined') { - if (req.time >= Date.now() - 10000) { - // 10s - return req.req; - } - this.pendingGetRequests.delete(init.url); - } - } else if ( - init.uploadImage || - init.uploadFilePUT || - init.uploadImageLegacy - ) { - // nothing - } else { - init.headers = { - 'Content-Type': 'application/json;charset=utf-8', - ...init.headers - }; - init.body = - params === Object(params) ? JSON.stringify(params) : '{}'; - } - var req = webApiService - .execute(init) - .catch((err) => { - this.$throw(0, err, endpoint); - }) - .then((response) => { - if (!response.data) { - if ($app.debugWebRequests) { - console.log(init, response); - } - return response; - } - try { - response.data = JSON.parse(response.data); - if ($app.debugWebRequests) { - console.log(init, response.data); - } - return response; - } catch (e) {} - if (response.status === 200) { - this.$throw( - 0, - $t('api.error.message.invalid_json_response'), - endpoint - ); - } - if ( - response.status === 429 && - init.url.endsWith('/instances/groups') - ) { - $app.nextGroupInstanceRefresh = 120; // 1min - throw new Error( - `${response.status}: rate limited ${endpoint}` - ); - } - if (response.status === 504 || response.status === 502) { - // ignore expected API errors - throw new Error( - `${response.status}: ${response.data} ${endpoint}` - ); - } - this.$throw(response.status, endpoint); - return {}; - }) - .then(({ data, status }) => { - if (status === 200) { - if (!data) { - return data; - } - var text = ''; - if (data.success === Object(data.success)) { - text = data.success.message; - } else if (data.OK === String(data.OK)) { - text = data.OK; - } - if (text) { - new Noty({ - type: 'success', - text: $app.escapeTag(text) - }).show(); - } - return data; - } - if ( - status === 401 && - data.error.message === '"Missing Credentials"' - ) { - this.$emit('AUTOLOGIN'); - throw new Error( - `401 ${$t('api.error.message.missing_credentials')}` - ); - } - if ( - status === 401 && - data.error.message === '"Unauthorized"' && - endpoint !== 'auth/user' - ) { - // trigger 2FA dialog - if (!$app.twoFactorAuthDialogVisible) { - $app.API.getCurrentUser(); - } - throw new Error(`401 ${$t('api.status_code.401')}`); - } - if (status === 403 && endpoint === 'config') { - $app.$alert( - $t('api.error.message.vpn_in_use'), - `403 ${$t('api.error.message.login_error')}` - ); - this.logout(); - throw new Error(`403 ${endpoint}`); - } - if ( - init.method === 'GET' && - status === 404 && - endpoint.startsWith('avatars/') - ) { - $app.$message({ - message: $t( - 'message.api_handler.avatar_private_or_deleted' - ), - type: 'error' - }); - $app.avatarDialog.visible = false; - throw new Error( - `404: ${data.error.message} ${endpoint}` - ); - } - if ( - status === 404 && - endpoint.endsWith('/persist/exists') - ) { - return false; - } - if ( - init.method === 'GET' && - (status === 404 || status === 403) && - !endpoint.startsWith('auth/user') - ) { - this.failedGetRequests.set(endpoint, Date.now()); - } - if ( - init.method === 'GET' && - status === 404 && - endpoint.startsWith('users/') && - endpoint.split('/').length - 1 === 1 - ) { - throw new Error( - `404: ${data.error.message} ${endpoint}` - ); - } - if ( - status === 404 && - endpoint.startsWith('invite/') && - init.inviteId - ) { - this.expireNotification(init.inviteId); - } - if ( - status === 403 && - endpoint.startsWith('invite/myself/to/') - ) { - throw new Error( - `403: ${data.error.message} ${endpoint}` - ); - } - if (data && data.error === Object(data.error)) { - this.$throw( - data.error.status_code || status, - data.error.message, - endpoint - ); - } else if (data && typeof data.error === 'string') { - this.$throw( - data.status_code || status, - data.error, - endpoint - ); - } - this.$throw(status, data, endpoint); - return data; - }); - if (init.method === 'GET') { - req.finally(() => { - this.pendingGetRequests.delete(init.url); - }); - this.pendingGetRequests.set(init.url, { - req, - time: Date.now() - }); - } - return req; - }; - - // FIXME : extra를 없애줘 - API.$throw = function (code, error, endpoint) { - var text = []; - if (code > 0) { - const status = this.statusCodes[code]; - if (typeof status === 'undefined') { - text.push(`${code}`); - } else { - const codeText = $t(`api.status_code.${code}`); - text.push(`${code} ${codeText}`); - } - } - if (typeof error !== 'undefined') { - text.push( - `${$t('api.error.message.error_message')}: ${typeof error === 'string' ? error : JSON.stringify(error)}` - ); - } - if (typeof endpoint !== 'undefined') { - text.push( - `${$t('api.error.message.endpoint')}: "${typeof endpoint === 'string' ? endpoint : JSON.stringify(endpoint)}"` - ); - } - text = text.map((s) => $app.escapeTag(s)).join('
'); - if (text.length) { - if (this.errorNoty) { - this.errorNoty.close(); - } - this.errorNoty = new Noty({ - type: 'error', - text - }).show(); - } - throw new Error(text); - }; - - API.$bulk = function (options, args) { - if ('handle' in options) { - options.handle.call(this, args, options); - } - if ( - args.json.length > 0 && - ((options.params.offset += args.json.length), - // eslint-disable-next-line no-nested-ternary - options.N > 0 - ? options.N > options.params.offset - : options.N < 0 - ? args.json.length - : options.params.n === args.json.length) - ) { - this.bulk(options); - } else if ('done' in options) { - options.done.call(this, true, options); - } - return args; - }; - - API.bulk = function (options) { - // it's stupid, but I won't waste time on the 'this' context - // works, that's enough. - if (typeof options.fn === 'function') { - options - .fn(options.params) - .catch((err) => { - if ('done' in options) { - options.done.call(this, false, options); - } - throw err; - }) - .then((args) => this.$bulk(options, args)); - } else { - this[options.fn](options.params) - .catch((err) => { - if ('done' in options) { - options.done.call(this, false, options); - } - throw err; - }) - .then((args) => this.$bulk(options, args)); - } - }; - - API.statusCodes = { - 100: 'Continue', - 101: 'Switching Protocols', - 102: 'Processing', - 103: 'Early Hints', - 200: 'OK', - 201: 'Created', - 202: 'Accepted', - 203: 'Non-Authoritative Information', - 204: 'No Content', - 205: 'Reset Content', - 206: 'Partial Content', - 207: 'Multi-Status', - 208: 'Already Reported', - 226: 'IM Used', - 300: 'Multiple Choices', - 301: 'Moved Permanently', - 302: 'Found', - 303: 'See Other', - 304: 'Not Modified', - 305: 'Use Proxy', - 306: 'Switch Proxy', - 307: 'Temporary Redirect', - 308: 'Permanent Redirect', - 400: 'Bad Request', - 401: 'Unauthorized', - 402: 'Payment Required', - 403: 'Forbidden', - 404: 'Not Found', - 405: 'Method Not Allowed', - 406: 'Not Acceptable', - 407: 'Proxy Authentication Required', - 408: 'Request Timeout', - 409: 'Conflict', - 410: 'Gone', - 411: 'Length Required', - 412: 'Precondition Failed', - 413: 'Payload Too Large', - 414: 'URI Too Long', - 415: 'Unsupported Media Type', - 416: 'Range Not Satisfiable', - 417: 'Expectation Failed', - 418: "I'm a teapot", - 421: 'Misdirected Request', - 422: 'Unprocessable Entity', - 423: 'Locked', - 424: 'Failed Dependency', - 425: 'Too Early', - 426: 'Upgrade Required', - 428: 'Precondition Required', - 429: 'Too Many Requests', - 431: 'Request Header Fields Too Large', - 451: 'Unavailable For Legal Reasons', - 500: 'Internal Server Error', - 501: 'Not Implemented', - 502: 'Bad Gateway', - 503: 'Service Unavailable', - 504: 'Gateway Timeout', - 505: 'HTTP Version Not Supported', - 506: 'Variant Also Negotiates', - 507: 'Insufficient Storage', - 508: 'Loop Detected', - 510: 'Not Extended', - 511: 'Network Authentication Required', - // CloudFlare Error - 520: 'Web server returns an unknown error', - 521: 'Web server is down', - 522: 'Connection timed out', - 523: 'Origin is unreachable', - 524: 'A timeout occurred', - 525: 'SSL handshake failed', - 526: 'Invalid SSL certificate', - 527: 'Railgun Listener to origin error' - }; - } -} diff --git a/src/classes/baseClass.js b/src/classes/baseClass.js deleted file mode 100644 index 963fa3ab..00000000 --- a/src/classes/baseClass.js +++ /dev/null @@ -1,28 +0,0 @@ -import $utils from './utils'; -/* eslint-disable no-unused-vars */ -let $app = {}; -let API = {}; -let $t = {}; -/* eslint-enable no-unused-vars */ - -class baseClass { - constructor(_app, _API, _t) { - $app = _app; - API = _API; - $t = _t; - - this.init(); - } - - updateRef(_app) { - $app = _app; - } - - init() {} - - _data = {}; - - _methods = {}; -} - -export { baseClass, $app, API, $t, $utils }; diff --git a/src/classes/currentUser.js b/src/classes/currentUser.js deleted file mode 100644 index 84ef3417..00000000 --- a/src/classes/currentUser.js +++ /dev/null @@ -1,325 +0,0 @@ -import { isRealInstance, parseLocation } from '../composables/instance/utils'; -import { $app, API, baseClass } from './baseClass.js'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - init() { - API.currentUser = { - $userColour: '' - }; - - API.getCurrentUser = function () { - return this.call('auth/user', { - method: 'GET' - }).then((json) => { - var args = { - json, - fromGetCurrentUser: true - }; - if ( - json.requiresTwoFactorAuth && - json.requiresTwoFactorAuth.includes('emailOtp') - ) { - this.$emit('USER:EMAILOTP', args); - } else if (json.requiresTwoFactorAuth) { - this.$emit('USER:2FA', args); - } else { - if ($app.debugCurrentUserDiff) { - var ref = args.json; - var $ref = this.currentUser; - var props = {}; - for (var prop in $ref) { - if ($ref[prop] !== Object($ref[prop])) { - props[prop] = true; - } - } - for (var prop in ref) { - if ( - Array.isArray(ref[prop]) && - Array.isArray($ref[prop]) - ) { - if (!$app.arraysMatch(ref[prop], $ref[prop])) { - props[prop] = true; - } - } else if (ref[prop] !== Object(ref[prop])) { - props[prop] = true; - } - } - var has = false; - for (var prop in props) { - var asis = $ref[prop]; - var tobe = ref[prop]; - if (asis === tobe) { - delete props[prop]; - } else { - if ( - prop.startsWith('$') || - prop === 'offlineFriends' || - prop === 'onlineFriends' || - prop === 'activeFriends' - ) { - delete props[prop]; - continue; - } - props[prop] = [tobe, asis]; - has = true; - } - } - if (has) { - console.log('API.getCurrentUser diff', props); - } - } - $app.nextCurrentUserRefresh = 420; // 7mins - this.$emit('USER:CURRENT', args); - } - return args; - }); - }; - - API.$on('USER:CURRENT', function (args) { - var { json } = args; - args.ref = this.applyCurrentUser(json); - - // when isGameRunning use gameLog instead of API - var $location = parseLocation($app.lastLocation.location); - var $travelingLocation = parseLocation( - $app.lastLocationDestination - ); - var location = $app.lastLocation.location; - var instanceId = $location.instanceId; - var worldId = $location.worldId; - var travelingToLocation = $app.lastLocationDestination; - var travelingToWorld = $travelingLocation.worldId; - var travelingToInstance = $travelingLocation.instanceId; - if (!$app.isGameRunning && json.presence) { - if (isRealInstance(json.presence.world)) { - location = `${json.presence.world}:${json.presence.instance}`; - } else { - location = json.presence.world; - } - if (isRealInstance(json.presence.travelingToWorld)) { - travelingToLocation = `${json.presence.travelingToWorld}:${json.presence.travelingToInstance}`; - } else { - travelingToLocation = json.presence.travelingToWorld; - } - instanceId = json.presence.instance; - worldId = json.presence.world; - travelingToInstance = json.presence.travelingToInstance; - travelingToWorld = json.presence.travelingToWorld; - } - this.applyUser({ - allowAvatarCopying: json.allowAvatarCopying, - badges: json.badges, - bio: json.bio, - bioLinks: json.bioLinks, - currentAvatarImageUrl: json.currentAvatarImageUrl, - currentAvatarTags: json.currentAvatarTags, - currentAvatarThumbnailImageUrl: - json.currentAvatarThumbnailImageUrl, - date_joined: json.date_joined, - developerType: json.developerType, - displayName: json.displayName, - friendKey: json.friendKey, - // json.friendRequestStatus - missing from currentUser - id: json.id, - // instanceId - missing from currentUser - isFriend: json.isFriend, - last_activity: json.last_activity, - last_login: json.last_login, - last_mobile: json.last_mobile, - last_platform: json.last_platform, - // location - missing from currentUser - // platform - missing from currentUser - // note - missing from currentUser - profilePicOverride: json.profilePicOverride, - // profilePicOverrideThumbnail - missing from currentUser - pronouns: json.pronouns, - state: json.state, - status: json.status, - statusDescription: json.statusDescription, - tags: json.tags, - // travelingToInstance - missing from currentUser - // travelingToLocation - missing from currentUser - // travelingToWorld - missing from currentUser - userIcon: json.userIcon, - // worldId - missing from currentUser - fallbackAvatar: json.fallbackAvatar, - - // Location from gameLog/presence - location, - instanceId, - worldId, - travelingToLocation, - travelingToInstance, - travelingToWorld, - - // set VRCX online/offline timers - $online_for: this.currentUser.$online_for, - $offline_for: this.currentUser.$offline_for, - $location_at: this.currentUser.$location_at, - $travelingToTime: this.currentUser.$travelingToTime - }); - }); - - API.applyCurrentUser = function (json) { - var ref = this.currentUser; - if (this.isLoggedIn) { - if (json.currentAvatar !== ref.currentAvatar) { - $app.addAvatarToHistory(json.currentAvatar); - if ($app.isGameRunning) { - $app.addAvatarWearTime(ref.currentAvatar); - ref.$previousAvatarSwapTime = Date.now(); - } - } - Object.assign(ref, json); - if (ref.homeLocation !== ref.$homeLocation.tag) { - ref.$homeLocation = parseLocation(ref.homeLocation); - // apply home location name to user dialog - if ( - $app.userDialog.visible && - $app.userDialog.id === ref.id - ) { - $app.getWorldName(API.currentUser.homeLocation).then( - (worldName) => { - $app.userDialog.$homeLocationName = worldName; - } - ); - } - } - ref.$isVRCPlus = ref.tags.includes('system_supporter'); - this.applyUserTrustLevel(ref); - this.applyUserLanguage(ref); - this.applyPresenceLocation(ref); - this.applyQueuedInstance(ref.queuedInstance); - this.applyPresenceGroups(ref); - } else { - ref = { - acceptedPrivacyVersion: 0, - acceptedTOSVersion: 0, - accountDeletionDate: null, - accountDeletionLog: null, - activeFriends: [], - ageVerificationStatus: '', - ageVerified: false, - allowAvatarCopying: false, - badges: [], - bio: '', - bioLinks: [], - currentAvatar: '', - currentAvatarImageUrl: '', - currentAvatarTags: [], - currentAvatarThumbnailImageUrl: '', - date_joined: '', - developerType: '', - displayName: '', - emailVerified: false, - fallbackAvatar: '', - friendGroupNames: [], - friendKey: '', - friends: [], - googleId: '', - hasBirthday: false, - hasEmail: false, - hasLoggedInFromClient: false, - hasPendingEmail: false, - hideContentFilterSettings: false, - homeLocation: '', - id: '', - isAdult: true, - isBoopingEnabled: false, - isFriend: false, - last_activity: '', - last_login: '', - last_mobile: null, - last_platform: '', - obfuscatedEmail: '', - obfuscatedPendingEmail: '', - oculusId: '', - offlineFriends: [], - onlineFriends: [], - pastDisplayNames: [], - picoId: '', - presence: { - avatarThumbnail: '', - currentAvatarTags: '', - displayName: '', - groups: [], - id: '', - instance: '', - instanceType: '', - platform: '', - profilePicOverride: '', - status: '', - travelingToInstance: '', - travelingToWorld: '', - userIcon: '', - world: '', - ...json.presence - }, - profilePicOverride: '', - pronouns: '', - queuedInstance: '', - state: '', - status: '', - statusDescription: '', - statusFirstTime: false, - statusHistory: [], - steamDetails: {}, - steamId: '', - tags: [], - twoFactorAuthEnabled: false, - twoFactorAuthEnabledDate: null, - unsubscribe: false, - updated_at: '', - userIcon: '', - userLanguage: '', - userLanguageCode: '', - username: '', - viveId: '', - // VRCX - $online_for: Date.now(), - $offline_for: '', - $location_at: Date.now(), - $travelingToTime: Date.now(), - $previousAvatarSwapTime: '', - $homeLocation: {}, - $isVRCPlus: false, - $isModerator: false, - $isTroll: false, - $isProbableTroll: false, - $trustLevel: 'Visitor', - $trustClass: 'x-tag-untrusted', - $userColour: '', - $trustSortNum: 1, - $languages: [], - $locationTag: '', - $travelingToLocation: '', - ...json - }; - if ($app.isGameRunning) { - ref.$previousAvatarSwapTime = Date.now(); - } - ref.$homeLocation = parseLocation(ref.homeLocation); - ref.$isVRCPlus = ref.tags.includes('system_supporter'); - this.applyUserTrustLevel(ref); - this.applyUserLanguage(ref); - this.applyPresenceLocation(ref); - this.applyPresenceGroups(ref); - this.currentUser = ref; - this.isLoggedIn = true; - this.$emit('LOGIN', { - json, - ref - }); - } - return ref; - }; - } - - _data = {}; - - _methods = {}; -} diff --git a/src/classes/discordRpc.js b/src/classes/discordRpc.js deleted file mode 100644 index d54946f1..00000000 --- a/src/classes/discordRpc.js +++ /dev/null @@ -1,291 +0,0 @@ -import { worldRequest } from '../api'; -import { parseLocation } from '../composables/instance/utils'; -import { getLaunchURL } from '../composables/shared/utils'; -import configRepository from '../service/config.js'; -import { API, baseClass } from './baseClass.js'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - _data = { - isDiscordActive: false, - discordActive: false, - discordInstance: true, - discordJoinButton: false, - discordHideInvite: true, - discordHideImage: false - }; - - _methods = { - updateDiscord() { - var currentLocation = this.lastLocation.location; - var timeStamp = this.lastLocation.date; - if (this.lastLocation.location === 'traveling') { - currentLocation = this.lastLocationDestination; - timeStamp = this.lastLocationDestinationTime; - } - if ( - !this.discordActive || - (!this.isGameRunning && !this.gameLogDisabled) || - (!currentLocation && !this.lastLocation$.tag) - ) { - this.setDiscordActive(false); - return; - } - this.setDiscordActive(true); - var L = this.lastLocation$; - if (currentLocation !== this.lastLocation$.tag) { - Discord.SetTimestamps(timeStamp, 0); - L = parseLocation(currentLocation); - L.worldName = ''; - L.thumbnailImageUrl = ''; - L.worldCapacity = 0; - L.joinUrl = ''; - L.accessName = ''; - if (L.worldId) { - var ref = API.cachedWorlds.get(L.worldId); - if (ref) { - L.worldName = ref.name; - L.thumbnailImageUrl = ref.thumbnailImageUrl; - L.worldCapacity = ref.capacity; - } else { - worldRequest - .getWorld({ - worldId: L.worldId - }) - .then((args) => { - L.worldName = args.ref.name; - L.thumbnailImageUrl = - args.ref.thumbnailImageUrl; - L.worldCapacity = args.ref.capacity; - return args; - }); - } - if (this.isGameNoVR) { - var platform = 'Desktop'; - } else { - var platform = 'VR'; - } - var groupAccessType = ''; - if (L.groupAccessType) { - if (L.groupAccessType === 'public') { - groupAccessType = 'Public'; - } else if (L.groupAccessType === 'plus') { - groupAccessType = 'Plus'; - } - } - switch (L.accessType) { - case 'public': - L.joinUrl = getLaunchURL(L); - L.accessName = `Public #${L.instanceName} (${platform})`; - break; - case 'invite+': - L.accessName = `Invite+ #${L.instanceName} (${platform})`; - break; - case 'invite': - L.accessName = `Invite #${L.instanceName} (${platform})`; - break; - case 'friends': - L.accessName = `Friends #${L.instanceName} (${platform})`; - break; - case 'friends+': - L.accessName = `Friends+ #${L.instanceName} (${platform})`; - break; - case 'group': - L.accessName = `Group #${L.instanceName} (${platform})`; - this.getGroupName(L.groupId).then((groupName) => { - if (groupName) { - L.accessName = `Group${groupAccessType}(${groupName}) #${L.instanceName} (${platform})`; - } - }); - break; - } - } - this.lastLocation$ = L; - } - var hidePrivate = false; - if ( - this.discordHideInvite && - (L.accessType === 'invite' || - L.accessType === 'invite+' || - L.groupAccessType === 'members') - ) { - hidePrivate = true; - } - switch (API.currentUser.status) { - case 'active': - L.statusName = 'Online'; - L.statusImage = 'active'; - break; - case 'join me': - L.statusName = 'Join Me'; - L.statusImage = 'joinme'; - break; - case 'ask me': - L.statusName = 'Ask Me'; - L.statusImage = 'askme'; - if (this.discordHideInvite) { - hidePrivate = true; - } - break; - case 'busy': - L.statusName = 'Do Not Disturb'; - L.statusImage = 'busy'; - hidePrivate = true; - break; - } - var appId = '883308884863901717'; - var bigIcon = 'vrchat'; - var partyId = `${L.worldId}:${L.instanceName}`; - var partySize = this.lastLocation.playerList.size; - var partyMaxSize = L.worldCapacity; - if (partySize > partyMaxSize) { - partyMaxSize = partySize; - } - var buttonText = 'Join'; - var buttonUrl = L.joinUrl; - if (!this.discordJoinButton) { - buttonText = ''; - buttonUrl = ''; - } - if (!this.discordInstance) { - partySize = 0; - partyMaxSize = 0; - } - if (hidePrivate) { - partyId = ''; - partySize = 0; - partyMaxSize = 0; - buttonText = ''; - buttonUrl = ''; - } else if (this.isRpcWorld(L.tag)) { - // custom world rpc - if ( - L.worldId === 'wrld_f20326da-f1ac-45fc-a062-609723b097b1' || - L.worldId === 'wrld_10e5e467-fc65-42ed-8957-f02cace1398c' || - L.worldId === 'wrld_04899f23-e182-4a8d-b2c7-2c74c7c15534' - ) { - appId = '784094509008551956'; - bigIcon = 'pypy'; - } else if ( - L.worldId === 'wrld_42377cf1-c54f-45ed-8996-5875b0573a83' || - L.worldId === 'wrld_dd6d2888-dbdc-47c2-bc98-3d631b2acd7c' - ) { - appId = '846232616054030376'; - bigIcon = 'vr_dancing'; - } else if ( - L.worldId === 'wrld_52bdcdab-11cd-4325-9655-0fb120846945' || - L.worldId === 'wrld_2d40da63-8f1f-4011-8a9e-414eb8530acd' - ) { - appId = '939473404808007731'; - bigIcon = 'zuwa_zuwa_dance'; - } else if ( - L.worldId === 'wrld_74970324-58e8-4239-a17b-2c59dfdf00db' || - L.worldId === 'wrld_db9d878f-6e76-4776-8bf2-15bcdd7fc445' || - L.worldId === 'wrld_435bbf25-f34f-4b8b-82c6-cd809057eb8e' || - L.worldId === 'wrld_f767d1c8-b249-4ecc-a56f-614e433682c8' - ) { - appId = '968292722391785512'; - bigIcon = 'ls_media'; - } else if ( - L.worldId === 'wrld_266523e8-9161-40da-acd0-6bd82e075833' - ) { - appId = '1095440531821170820'; - bigIcon = 'movie_and_chill'; - } - if (this.nowPlaying.name) { - L.worldName = this.nowPlaying.name; - } - if (this.nowPlaying.playing) { - Discord.SetTimestamps( - Date.now(), - (this.nowPlaying.startTime - - this.nowPlaying.offset + - this.nowPlaying.length) * - 1000 - ); - } - } else if (!this.discordHideImage && L.thumbnailImageUrl) { - bigIcon = L.thumbnailImageUrl; - } - Discord.SetAssets( - bigIcon, // big icon - 'Powered by VRCX', // big icon hover text - L.statusImage, // small icon - L.statusName, // small icon hover text - partyId, // party id - partySize, // party size - partyMaxSize, // party max size - buttonText, // button text - buttonUrl, // button url - appId // app id - ); - // NOTE - // 글자 수가 짧으면 업데이트가 안된다.. - if (L.worldName.length < 2) { - L.worldName += '\uFFA0'.repeat(2 - L.worldName.length); - } - if (hidePrivate) { - Discord.SetText('Private', ''); - Discord.SetTimestamps(0, 0); - } else if (this.discordInstance) { - Discord.SetText(L.worldName, L.accessName); - } else { - Discord.SetText(L.worldName, ''); - } - }, - - async setDiscordActive(active) { - if (active !== this.isDiscordActive) { - this.isDiscordActive = await Discord.SetActive(active); - } - }, - - async saveDiscordOption(configLabel = '') { - if (configLabel === 'discordActive') { - this.discordActive = !this.discordActive; - await configRepository.setBool( - 'discordActive', - this.discordActive - ); - } - - if (configLabel === 'discordInstance') { - this.discordInstance = !this.discordInstance; - await configRepository.setBool( - 'discordInstance', - this.discordInstance - ); - } - - if (configLabel === 'discordJoinButton') { - this.discordJoinButton = !this.discordJoinButton; - await configRepository.setBool( - 'discordJoinButton', - this.discordJoinButton - ); - } - - if (configLabel === 'discordHideInvite') { - this.discordHideInvite = !this.discordHideInvite; - await configRepository.setBool( - 'discordHideInvite', - this.discordHideInvite - ); - } - if (configLabel === 'discordHideImage') { - this.discordHideImage = !this.discordHideImage; - await configRepository.setBool( - 'discordHideImage', - this.discordHideImage - ); - } - - this.lastLocation$.tag = ''; - this.nextDiscordUpdate = 3; - this.updateDiscord(); - } - }; -} diff --git a/src/classes/feed.js b/src/classes/feed.js deleted file mode 100644 index 9c427e1e..00000000 --- a/src/classes/feed.js +++ /dev/null @@ -1,179 +0,0 @@ -import { baseClass, $app, API, $t, $utils } from './baseClass.js'; -import configRepository from '../service/config.js'; -import database from '../service/database.js'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - _data = { - feedTable: { - data: [], - search: '', - vip: false, - loading: false, - filter: [], - tableProps: { - stripe: true, - size: 'mini', - defaultSort: { - prop: 'created_at', - order: 'descending' - } - }, - pageSize: 15, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [10, 15, 20, 25, 50, 100] - } - }, - - feedSessionTable: [] - }; - - _methods = { - feedSearch(row) { - var value = this.feedTable.search.toUpperCase(); - if (!value) { - return true; - } - if ( - (value.startsWith('wrld_') || value.startsWith('grp_')) && - String(row.location).toUpperCase().includes(value) - ) { - return true; - } - switch (row.type) { - case 'GPS': - if (String(row.displayName).toUpperCase().includes(value)) { - return true; - } - if (String(row.worldName).toUpperCase().includes(value)) { - return true; - } - return false; - case 'Online': - if (String(row.displayName).toUpperCase().includes(value)) { - return true; - } - if (String(row.worldName).toUpperCase().includes(value)) { - return true; - } - return false; - case 'Offline': - if (String(row.displayName).toUpperCase().includes(value)) { - return true; - } - if (String(row.worldName).toUpperCase().includes(value)) { - return true; - } - return false; - case 'Status': - if (String(row.displayName).toUpperCase().includes(value)) { - return true; - } - if (String(row.status).toUpperCase().includes(value)) { - return true; - } - if ( - String(row.statusDescription) - .toUpperCase() - .includes(value) - ) { - return true; - } - return false; - case 'Avatar': - if (String(row.displayName).toUpperCase().includes(value)) { - return true; - } - if (String(row.avatarName).toUpperCase().includes(value)) { - return true; - } - return false; - case 'Bio': - if (String(row.displayName).toUpperCase().includes(value)) { - return true; - } - if (String(row.bio).toUpperCase().includes(value)) { - return true; - } - if (String(row.previousBio).toUpperCase().includes(value)) { - return true; - } - return false; - } - return true; - }, - - async feedTableLookup() { - await configRepository.setString( - 'VRCX_feedTableFilters', - JSON.stringify(this.feedTable.filter) - ); - await configRepository.setBool( - 'VRCX_feedTableVIPFilter', - this.feedTable.vip - ); - this.feedTable.loading = true; - var vipList = []; - if (this.feedTable.vip) { - vipList = Array.from(this.localFavoriteFriends.values()); - } - this.feedTable.data = await database.lookupFeedDatabase( - this.feedTable.search, - this.feedTable.filter, - vipList - ); - this.feedTable.loading = false; - }, - - addFeed(feed) { - this.queueFeedNoty(feed); - this.feedSessionTable.push(feed); - this.updateSharedFeed(false); - if ( - this.feedTable.filter.length > 0 && - !this.feedTable.filter.includes(feed.type) - ) { - return; - } - if ( - this.feedTable.vip && - !this.localFavoriteFriends.has(feed.userId) - ) { - return; - } - if (!this.feedSearch(feed)) { - return; - } - this.feedTable.data.push(feed); - this.sweepFeed(); - this.notifyMenu('feed'); - }, - - sweepFeed() { - var { data } = this.feedTable; - var j = data.length; - if (j > this.maxTableSize) { - data.splice(0, j - this.maxTableSize); - } - - var date = new Date(); - date.setDate(date.getDate() - 1); // 24 hour limit - var limit = date.toJSON(); - var i = 0; - var k = this.feedSessionTable.length; - while (i < k && this.feedSessionTable[i].created_at < limit) { - ++i; - } - if (i === k) { - this.feedSessionTable = []; - } else if (i) { - this.feedSessionTable.splice(0, i); - } - } - }; -} diff --git a/src/classes/gameLog.js b/src/classes/gameLog.js deleted file mode 100644 index ff32d0dc..00000000 --- a/src/classes/gameLog.js +++ /dev/null @@ -1,1138 +0,0 @@ -import * as workerTimers from 'worker-timers'; -import { parseLocation } from '../composables/instance/utils'; -import gameLogService from '../service/gamelog.js'; -import configRepository from '../service/config.js'; -import database from '../service/database.js'; -import { baseClass, $app, API, $utils } from './baseClass.js'; -import { userRequest } from '../api'; -import dayjs from 'dayjs'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - _data = { - gameLogTable: { - data: [], - loading: false, - search: '', - filter: [], - tableProps: { - stripe: true, - size: 'mini', - defaultSort: { - prop: 'created_at', - order: 'descending' - } - }, - pageSize: 15, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [10, 15, 20, 25, 50, 100] - } - }, - gameLogSessionTable: [], - lastVideoUrl: '', - lastResourceloadUrl: '' - }; - - _methods = { - addGameLogEntry(gameLog, location) { - if (this.gameLogDisabled) { - return; - } - var userId = String(gameLog.userId || ''); - if (!userId && gameLog.displayName) { - for (var ref of API.cachedUsers.values()) { - if (ref.displayName === gameLog.displayName) { - userId = ref.id; - break; - } - } - } - switch (gameLog.type) { - case 'location-destination': - if (this.isGameRunning) { - // needs to be added before OnPlayerLeft entries from LocationReset - this.addGameLog({ - created_at: gameLog.dt, - type: 'LocationDestination', - location: gameLog.location - }); - this.lastLocationReset(gameLog.dt); - this.lastLocation.location = 'traveling'; - this.lastLocationDestination = gameLog.location; - this.lastLocationDestinationTime = Date.parse( - gameLog.dt - ); - this.removeQueuedInstance(gameLog.location); - this.updateCurrentUserLocation(); - this.clearNowPlaying(); - this.updateCurrentInstanceWorld(); - this.applyUserDialogLocation(); - this.applyWorldDialogInstances(); - this.applyGroupDialogInstances(); - } - break; - case 'location': - this.addInstanceJoinHistory( - this.lastLocation.location, - gameLog.dt - ); - var worldName = $utils.replaceBioSymbols(gameLog.worldName); - if (this.isGameRunning) { - this.lastLocationReset(gameLog.dt); - this.clearNowPlaying(); - this.lastLocation = { - date: Date.parse(gameLog.dt), - location: gameLog.location, - name: worldName, - playerList: new Map(), - friendList: new Map() - }; - this.removeQueuedInstance(gameLog.location); - this.updateCurrentUserLocation(); - this.updateVRLastLocation(); - this.updateCurrentInstanceWorld(); - this.applyUserDialogLocation(); - this.applyWorldDialogInstances(); - this.applyGroupDialogInstances(); - } - this.addInstanceJoinHistory(gameLog.location, gameLog.dt); - var L = parseLocation(gameLog.location); - var entry = { - created_at: gameLog.dt, - type: 'Location', - location: gameLog.location, - worldId: L.worldId, - worldName, - groupName: '', - time: 0 - }; - this.getGroupName(gameLog.location).then((groupName) => { - entry.groupName = groupName; - }); - this.addGamelogLocationToDatabase(entry); - break; - case 'player-joined': - var joinTime = Date.parse(gameLog.dt); - var userMap = { - displayName: gameLog.displayName, - userId, - joinTime, - lastAvatar: '' - }; - this.lastLocation.playerList.set(userId, userMap); - var ref = API.cachedUsers.get(userId); - if (!userId) { - console.error('Missing userId:', gameLog.displayName); - } else if (userId === API.currentUser.id) { - // skip - } else if (this.friends.has(userId)) { - this.lastLocation.friendList.set(userId, userMap); - if ( - ref.location !== this.lastLocation.location && - ref.travelingToLocation !== - this.lastLocation.location - ) { - // fix $location_at with private - ref.$location_at = joinTime; - } - } else if (typeof ref !== 'undefined') { - // set $location_at to join time if user isn't a friend - ref.$location_at = joinTime; - } else { - if (this.debugGameLog || this.debugWebRequests) { - console.log('Fetching user from gameLog:', userId); - } - userRequest.getUser({ userId }); - } - this.updateVRLastLocation(); - this.getCurrentInstanceUserList(); - var entry = { - created_at: gameLog.dt, - type: 'OnPlayerJoined', - displayName: gameLog.displayName, - location, - userId, - time: 0 - }; - database.addGamelogJoinLeaveToDatabase(entry); - break; - case 'player-left': - var ref = this.lastLocation.playerList.get(userId); - if (typeof ref === 'undefined') { - break; - } - var friendRef = this.friends.get(userId); - if (typeof friendRef?.ref !== 'undefined') { - friendRef.ref.$joinCount++; - friendRef.ref.$lastSeen = new Date().toJSON(); - friendRef.ref.$timeSpent += - dayjs(gameLog.dt) - ref.joinTime; - if ( - this.sidebarSortMethods.includes( - 'Sort by Last Seen' - ) - ) { - this.sortVIPFriends = true; - this.sortOnlineFriends = true; - } - } - var time = dayjs(gameLog.dt) - ref.joinTime; - this.lastLocation.playerList.delete(userId); - this.lastLocation.friendList.delete(userId); - this.photonLobbyAvatars.delete(userId); - this.updateVRLastLocation(); - this.getCurrentInstanceUserList(); - var entry = { - created_at: gameLog.dt, - type: 'OnPlayerLeft', - displayName: gameLog.displayName, - location, - userId, - time - }; - database.addGamelogJoinLeaveToDatabase(entry); - break; - case 'portal-spawn': - if (this.ipcEnabled && this.isGameRunning) { - break; - } - var entry = { - created_at: gameLog.dt, - type: 'PortalSpawn', - location, - displayName: '', - userId: '', - instanceId: '', - worldName: '' - }; - database.addGamelogPortalSpawnToDatabase(entry); - break; - case 'video-play': - gameLog.videoUrl = decodeURI(gameLog.videoUrl); - if (this.lastVideoUrl === gameLog.videoUrl) { - break; - } - this.lastVideoUrl = gameLog.videoUrl; - this.addGameLogVideo(gameLog, location, userId); - break; - case 'video-sync': - var timestamp = gameLog.timestamp.replace(/,/g, ''); - if (this.nowPlaying.playing) { - this.nowPlaying.offset = parseInt(timestamp, 10); - } - break; - case 'resource-load-string': - case 'resource-load-image': - if ( - !this.logResourceLoad || - this.lastResourceloadUrl === gameLog.resourceUrl - ) { - break; - } - this.lastResourceloadUrl = gameLog.resourceUrl; - var entry = { - created_at: gameLog.dt, - type: - gameLog.type === 'resource-load-string' - ? 'StringLoad' - : 'ImageLoad', - resourceUrl: gameLog.resourceUrl, - location - }; - database.addGamelogResourceLoadToDatabase(entry); - break; - case 'screenshot': - // var entry = { - // created_at: gameLog.dt, - // type: 'Event', - // data: `Screenshot Processed: ${gameLog.screenshotPath.replace( - // /^.*[\\/]/, - // '' - // )}` - // }; - // database.addGamelogEventToDatabase(entry); - - this.processScreenshot(gameLog.screenshotPath); - break; - case 'api-request': - if ($app.debugWebRequests) { - console.log('API Request:', gameLog.url); - } - - // var userId = ''; - // try { - // var url = new URL(gameLog.url); - // var urlParams = new URLSearchParams(gameLog.url); - // if (url.pathname.substring(0, 13) === '/api/1/users/') { - // var pathArray = url.pathname.split('/'); - // userId = pathArray[4]; - // } else if (urlParams.has('userId')) { - // userId = urlParams.get('userId'); - // } - // } catch (err) { - // console.error(err); - // } - // if (!userId) { - // break; - // } - - if ($app.saveInstanceEmoji) { - try { - // https://api.vrchat.cloud/api/1/user/usr_032383a7-748c-4fb2-94e4-bcb928e5de6b/inventory/inv_75781d65-92fe-4a80-a1ff-27ee6e843b08 - const url = new URL(gameLog.url); - if ( - url.pathname.substring(0, 12) === - '/api/1/user/' && - url.pathname.includes('/inventory/inv_') - ) { - const pathArray = url.pathname.split('/'); - const userId = pathArray[4]; - const inventoryId = pathArray[6]; - if (userId && inventoryId.length === 40) { - $app.queueCheckInstanceInventory( - inventoryId, - userId - ); - } - } - } catch (err) { - console.error(err); - } - } - - if ($app.saveInstancePrints) { - try { - let printId = ''; - const url1 = new URL(gameLog.url); - if ( - url1.pathname.substring(0, 14) === - '/api/1/prints/' - ) { - const pathArray = url1.pathname.split('/'); - printId = pathArray[4]; - } - if (printId && printId.length === 41) { - $app.queueSavePrintToFile(printId); - } - } catch (err) { - console.error(err); - } - } - break; - case 'avatar-change': - var ref = this.lastLocation.playerList.get(userId); - if ( - this.photonLoggingEnabled || - typeof ref === 'undefined' || - ref.lastAvatar === gameLog.avatarName - ) { - break; - } - if (!ref.lastAvatar) { - ref.lastAvatar = gameLog.avatarName; - this.lastLocation.playerList.set(userId, ref); - break; - } - ref.lastAvatar = gameLog.avatarName; - this.lastLocation.playerList.set(userId, ref); - var entry = { - created_at: gameLog.dt, - type: 'AvatarChange', - userId, - name: gameLog.avatarName, - displayName: gameLog.displayName - }; - break; - case 'vrcx': - // VideoPlay(PyPyDance) "https://jd.pypy.moe/api/v1/videos/jr1NX4Jo8GE.mp4",0.1001,239.606,"0905 : [J-POP] 【まなこ】金曜日のおはよう 踊ってみた (vernities)" - var type = gameLog.data.substr( - 0, - gameLog.data.indexOf(' ') - ); - if (type === 'VideoPlay(PyPyDance)') { - this.addGameLogPyPyDance(gameLog, location); - } else if (type === 'VideoPlay(VRDancing)') { - this.addGameLogVRDancing(gameLog, location); - } else if (type === 'VideoPlay(ZuwaZuwaDance)') { - this.addGameLogZuwaZuwaDance(gameLog, location); - } else if (type === 'LSMedia') { - this.addGameLogLSMedia(gameLog, location); - } else if (type === 'Movie&Chill') { - this.addGameLogMovieAndChill(gameLog, location); - } - break; - case 'photon-id': - if (!this.isGameRunning || !this.friendLogInitStatus) { - break; - } - var photonId = parseInt(gameLog.photonId, 10); - var ref = this.photonLobby.get(photonId); - if (typeof ref === 'undefined') { - for (var ctx of API.cachedUsers.values()) { - if (ctx.displayName === gameLog.displayName) { - this.photonLobby.set(photonId, ctx); - this.photonLobbyCurrent.set(photonId, ctx); - break; - } - } - var ctx = { - displayName: gameLog.displayName - }; - this.photonLobby.set(photonId, ctx); - this.photonLobbyCurrent.set(photonId, ctx); - this.getCurrentInstanceUserList(); - } - break; - case 'notification': - // var entry = { - // created_at: gameLog.dt, - // type: 'Notification', - // data: gameLog.json - // }; - break; - case 'event': - var entry = { - created_at: gameLog.dt, - type: 'Event', - data: gameLog.event - }; - database.addGamelogEventToDatabase(entry); - break; - case 'vrc-quit': - if (!this.isGameRunning) { - break; - } - if (this.vrcQuitFix) { - var bias = Date.parse(gameLog.dt) + 3000; - if (bias < Date.now()) { - console.log( - 'QuitFix: Bias too low, not killing VRC' - ); - break; - } - AppApi.QuitGame().then((processCount) => { - if (processCount > 1) { - console.log( - 'QuitFix: More than 1 process running, not killing VRC' - ); - } else if (processCount === 1) { - console.log('QuitFix: Killed VRC'); - } else { - console.log( - 'QuitFix: Nothing to kill, no VRC process running' - ); - } - }); - } - break; - case 'openvr-init': - this.isGameNoVR = false; - configRepository.setBool('isGameNoVR', this.isGameNoVR); - this.updateOpenVR(); - break; - case 'desktop-mode': - this.isGameNoVR = true; - configRepository.setBool('isGameNoVR', this.isGameNoVR); - this.updateOpenVR(); - break; - case 'udon-exception': - if (this.udonExceptionLogging) { - console.log('UdonException', gameLog.data); - } - // var entry = { - // created_at: gameLog.dt, - // type: 'Event', - // data: gameLog.data - // }; - // database.addGamelogEventToDatabase(entry); - break; - case 'sticker-spawn': - if (!$app.saveInstanceStickers) { - break; - } - - $app.trySaveStickerToFile( - gameLog.displayName, - gameLog.userId, - gameLog.inventoryId - ); - break; - } - if (entry) { - // add tag colour - if (entry.userId) { - var tagRef = this.customUserTags.get(entry.userId); - if (typeof tagRef !== 'undefined') { - entry.tagColour = tagRef.colour; - } - } - this.queueGameLogNoty(entry); - this.addGameLog(entry); - } - }, - - addGameLog(entry) { - this.gameLogSessionTable.push(entry); - this.updateSharedFeed(false); - if (entry.type === 'VideoPlay') { - // event time can be before last gameLog entry - this.updateSharedFeed(true); - } - - // If the VIP friend filter is enabled, logs from other friends will be ignored. - if ( - this.gameLogTable.vip && - !this.localFavoriteFriends.has(entry.userId) && - (entry.type === 'OnPlayerJoined' || - entry.type === 'OnPlayerLeft' || - entry.type === 'VideoPlay' || - entry.type === 'PortalSpawn' || - entry.type === 'External') - ) { - return; - } - if ( - entry.type === 'LocationDestination' || - entry.type === 'AvatarChange' || - entry.type === 'ChatBoxMessage' || - (entry.userId === API.currentUser.id && - (entry.type === 'OnPlayerJoined' || - entry.type === 'OnPlayerLeft')) - ) { - return; - } - if ( - this.gameLogTable.filter.length > 0 && - !this.gameLogTable.filter.includes(entry.type) - ) { - return; - } - if (!this.gameLogSearch(entry)) { - return; - } - this.gameLogTable.data.push(entry); - this.sweepGameLog(); - this.notifyMenu('gameLog'); - }, - - async addGamelogLocationToDatabase(input) { - var groupName = await this.getGroupName(input.location); - var entry = { - ...input, - groupName - }; - database.addGamelogLocationToDatabase(entry); - }, - - async addGameLogVideo(gameLog, location, userId) { - var videoUrl = gameLog.videoUrl; - var youtubeVideoId = ''; - var videoId = ''; - var videoName = ''; - var videoLength = ''; - var displayName = ''; - var videoPos = 8; // video loading delay - if (typeof gameLog.displayName !== 'undefined') { - displayName = gameLog.displayName; - } - if (typeof gameLog.videoPos !== 'undefined') { - videoPos = gameLog.videoPos; - } - if (!this.isRpcWorld(location) || gameLog.videoId === 'YouTube') { - // skip PyPyDance and VRDancing videos - try { - var url = new URL(videoUrl); - if ( - url.origin === 'https://t-ne.x0.to' || - url.origin === 'https://nextnex.com' || - url.origin === 'https://r.0cm.org' - ) { - url = new URL(url.searchParams.get('url')); - } - if (videoUrl.startsWith('https://u2b.cx/')) { - url = new URL(videoUrl.substring(15)); - } - var id1 = url.pathname; - var id2 = url.searchParams.get('v'); - if (id1 && id1.length === 12) { - // https://youtu.be/ - youtubeVideoId = id1.substring(1, 12); - } - if (id1 && id1.length === 19) { - // https://www.youtube.com/shorts/ - youtubeVideoId = id1.substring(8, 19); - } - if (id2 && id2.length === 11) { - // https://www.youtube.com/watch?v= - // https://music.youtube.com/watch?v= - youtubeVideoId = id2; - } - if (this.youTubeApi && youtubeVideoId) { - var data = - await this.lookupYouTubeVideo(youtubeVideoId); - if (data || data.pageInfo.totalResults !== 0) { - videoId = 'YouTube'; - videoName = data.items[0].snippet.title; - videoLength = this.convertYoutubeTime( - data.items[0].contentDetails.duration - ); - } - } - } catch { - console.error(`Invalid URL: ${url}`); - } - var entry = { - created_at: gameLog.dt, - type: 'VideoPlay', - videoUrl, - videoId, - videoName, - videoLength, - location, - displayName, - userId, - videoPos - }; - this.setNowPlaying(entry); - } - }, - - addGameLogPyPyDance(gameLog, location) { - var data = - /VideoPlay\(PyPyDance\) "(.+?)",([\d.]+),([\d.]+),"(.*)"/g.exec( - gameLog.data - ); - if (!data) { - console.error('failed to parse', gameLog.data); - return; - } - var videoUrl = data[1]; - var videoPos = Number(data[2]); - var videoLength = Number(data[3]); - var title = data[4]; - var bracketArray = title.split('('); - var text1 = bracketArray.pop(); - var displayName = text1.slice(0, -1); - var text2 = bracketArray.join('('); - if (text2 === 'Custom URL') { - var videoId = 'YouTube'; - } else { - var videoId = text2.substr(0, text2.indexOf(':') - 1); - text2 = text2.substr(text2.indexOf(':') + 2); - } - var videoName = text2.slice(0, -1); - if (displayName === 'Random') { - displayName = ''; - } - if (videoUrl === this.nowPlaying.url) { - var entry = { - created_at: gameLog.dt, - videoUrl, - videoLength, - videoPos - }; - this.setNowPlaying(entry); - return; - } - var userId = ''; - if (displayName) { - for (var ref of API.cachedUsers.values()) { - if (ref.displayName === displayName) { - userId = ref.id; - break; - } - } - } - if (videoId === 'YouTube') { - var entry = { - dt: gameLog.dt, - videoUrl, - displayName, - videoPos, - videoId - }; - this.addGameLogVideo(entry, location, userId); - } else { - var entry = { - created_at: gameLog.dt, - type: 'VideoPlay', - videoUrl, - videoId, - videoName, - videoLength, - location, - displayName, - userId, - videoPos - }; - this.setNowPlaying(entry); - } - }, - - addGameLogVRDancing(gameLog, location) { - var data = - /VideoPlay\(VRDancing\) "(.+?)",([\d.]+),([\d.]+),(-?[\d.]+),"(.+?)","(.+?)"/g.exec( - gameLog.data - ); - if (!data) { - console.error('failed to parse', gameLog.data); - return; - } - var videoUrl = data[1]; - var videoPos = Number(data[2]); - var videoLength = Number(data[3]); - var videoId = Number(data[4]); - var displayName = data[5]; - var videoName = data[6]; - if (videoId === -1) { - videoId = 'YouTube'; - } - if (parseInt(videoPos, 10) === parseInt(videoLength, 10)) { - // ummm okay - videoPos = 0; - } - if (videoUrl === this.nowPlaying.url) { - var entry = { - created_at: gameLog.dt, - videoUrl, - videoLength, - videoPos - }; - this.setNowPlaying(entry); - return; - } - var userId = ''; - if (displayName) { - for (var ref of API.cachedUsers.values()) { - if (ref.displayName === displayName) { - userId = ref.id; - break; - } - } - } - if (videoId === 'YouTube') { - var entry = { - dt: gameLog.dt, - videoUrl, - displayName, - videoPos, - videoId - }; - this.addGameLogVideo(entry, location, userId); - } else { - var entry = { - created_at: gameLog.dt, - type: 'VideoPlay', - videoUrl, - videoId, - videoName, - videoLength, - location, - displayName, - userId, - videoPos - }; - this.setNowPlaying(entry); - } - }, - - addGameLogZuwaZuwaDance(gameLog, location) { - var data = - /VideoPlay\(ZuwaZuwaDance\) "(.+?)",([\d.]+),([\d.]+),(-?[\d.]+),"(.+?)","(.+?)"/g.exec( - gameLog.data - ); - if (!data) { - console.error('failed to parse', gameLog.data); - return; - } - var videoUrl = data[1]; - var videoPos = Number(data[2]); - var videoLength = Number(data[3]); - var videoId = Number(data[4]); - var displayName = data[5]; - var videoName = data[6]; - if (displayName === 'Random') { - displayName = ''; - } - if (videoId === 9999) { - videoId = 'YouTube'; - } - if (videoUrl === this.nowPlaying.url) { - var entry = { - created_at: gameLog.dt, - videoUrl, - videoLength, - videoPos - }; - this.setNowPlaying(entry); - return; - } - var userId = ''; - if (displayName) { - for (var ref of API.cachedUsers.values()) { - if (ref.displayName === displayName) { - userId = ref.id; - break; - } - } - } - if (videoId === 'YouTube') { - var entry = { - dt: gameLog.dt, - videoUrl, - displayName, - videoPos, - videoId - }; - this.addGameLogVideo(entry, location, userId); - } else { - var entry = { - created_at: gameLog.dt, - type: 'VideoPlay', - videoUrl, - videoId, - videoName, - videoLength, - location, - displayName, - userId, - videoPos - }; - this.setNowPlaying(entry); - } - }, - - addGameLogLSMedia(gameLog, location) { - // [VRCX] LSMedia 0,4268.981,Natsumi-sama,, - // [VRCX] LSMedia 0,6298.292,Natsumi-sama,The Outfit (2022), 1080p - var data = /LSMedia ([\d.]+),([\d.]+),(.+?),(.+?),(?=[^,]*$)/g.exec( - gameLog.data - ); - if (!data) { - return; - } - var videoPos = Number(data[1]); - var videoLength = Number(data[2]); - var displayName = data[3]; - var videoName = $utils.replaceBioSymbols(data[4]); - var videoUrl = videoName; - var videoId = 'LSMedia'; - if (videoUrl === this.nowPlaying.url) { - var entry = { - created_at: gameLog.dt, - videoUrl, - videoLength, - videoPos - }; - this.setNowPlaying(entry); - return; - } - var userId = ''; - if (displayName) { - for (var ref of API.cachedUsers.values()) { - if (ref.displayName === displayName) { - userId = ref.id; - break; - } - } - } - var entry = { - created_at: gameLog.dt, - type: 'VideoPlay', - videoUrl, - videoId, - videoName, - videoLength, - location, - displayName, - userId, - videoPos - }; - this.setNowPlaying(entry); - }, - - addGameLogMovieAndChill(gameLog, location) { - // [VRCX] Movie&Chill CurrentTime,Length,PlayerName,MovieName - var data = /Movie&Chill ([\d.]+),([\d.]+),(.+?),(.*)/g.exec( - gameLog.data - ); - if (!data) { - return; - } - var videoPos = Number(data[1]); - var videoLength = Number(data[2]); - var displayName = data[3]; - var videoName = data[4]; - var videoUrl = videoName; - var videoId = 'Movie&Chill'; - if (!videoName) { - return; - } - if (videoUrl === this.nowPlaying.url) { - var entry = { - created_at: gameLog.dt, - videoUrl, - videoLength, - videoPos - }; - this.setNowPlaying(entry); - return; - } - var userId = ''; - if (displayName) { - for (var ref of API.cachedUsers.values()) { - if (ref.displayName === displayName) { - userId = ref.id; - break; - } - } - } - var entry = { - created_at: gameLog.dt, - type: 'VideoPlay', - videoUrl, - videoId, - videoName, - videoLength, - location, - displayName, - userId, - videoPos - }; - this.setNowPlaying(entry); - }, - - async gameLogTableLookup() { - await configRepository.setString( - 'VRCX_gameLogTableFilters', - JSON.stringify(this.gameLogTable.filter) - ); - await configRepository.setBool( - 'VRCX_gameLogTableVIPFilter', - this.gameLogTable.vip - ); - this.gameLogTable.loading = true; - let vipList = []; - if (this.gameLogTable.vip) { - vipList = Array.from(this.localFavoriteFriends.values()); - } - this.gameLogTable.data = await database.lookupGameLogDatabase( - this.gameLogTable.search, - this.gameLogTable.filter, - vipList - ); - this.gameLogTable.loading = false; - }, - - sweepGameLog() { - var { data } = this.gameLogTable; - var j = data.length; - if (j > this.maxTableSize) { - data.splice(0, j - this.maxTableSize); - } - - var date = new Date(); - date.setDate(date.getDate() - 1); // 24 hour limit - var limit = date.toJSON(); - var i = 0; - var k = this.gameLogSessionTable.length; - while (i < k && this.gameLogSessionTable[i].created_at < limit) { - ++i; - } - if (i === k) { - this.gameLogSessionTable = []; - } else if (i) { - this.gameLogSessionTable.splice(0, i); - } - }, - - // async resetGameLog() { - // await gameLogService.reset(); - // this.gameLogTable.data = []; - // this.lastLocationReset(); - // }, - - // async refreshEntireGameLog() { - // await gameLogService.setDateTill('1970-01-01'); - // await database.initTables(); - // await this.resetGameLog(); - // var location = ''; - // for (var gameLog of await gameLogService.getAll()) { - // if (gameLog.type === 'location') { - // location = gameLog.location; - // } - // this.addGameLogEntry(gameLog, location); - // } - // this.getGameLogTable(); - // }, - - async getGameLogTable() { - await database.initTables(); - this.gameLogSessionTable = await database.getGamelogDatabase(); - var dateTill = await database.getLastDateGameLogDatabase(); - this.updateGameLog(dateTill); - }, - - async updateGameLog(dateTill) { - await gameLogService.setDateTill(dateTill); - await new Promise((resolve) => { - workerTimers.setTimeout(resolve, 10000); - }); - var location = ''; - for (var gameLog of await gameLogService.getAll()) { - if (gameLog.type === 'location') { - location = gameLog.location; - } - this.addGameLogEntry(gameLog, location); - } - }, - - addGameLogEvent(json) { - var rawLogs = JSON.parse(json); - var gameLog = gameLogService.parseRawGameLog( - rawLogs[1], - rawLogs[2], - rawLogs.slice(3) - ); - if ( - this.debugGameLog && - gameLog.type !== 'photon-id' && - gameLog.type !== 'api-request' && - gameLog.type !== 'udon-exception' - ) { - console.log('gameLog:', gameLog); - } - this.addGameLogEntry(gameLog, this.lastLocation.location); - }, - - gameLogSearch(row) { - var value = this.gameLogTable.search.toUpperCase(); - if (!value) { - return true; - } - if ( - (value.startsWith('wrld_') || value.startsWith('grp_')) && - String(row.location).toUpperCase().includes(value) - ) { - return true; - } - switch (row.type) { - case 'Location': - if (String(row.worldName).toUpperCase().includes(value)) { - return true; - } - return false; - case 'OnPlayerJoined': - if (String(row.displayName).toUpperCase().includes(value)) { - return true; - } - return false; - case 'OnPlayerLeft': - if (String(row.displayName).toUpperCase().includes(value)) { - return true; - } - return false; - case 'PortalSpawn': - if (String(row.displayName).toUpperCase().includes(value)) { - return true; - } - if (String(row.worldName).toUpperCase().includes(value)) { - return true; - } - return false; - case 'Event': - if (String(row.data).toUpperCase().includes(value)) { - return true; - } - return false; - case 'External': - if (String(row.message).toUpperCase().includes(value)) { - return true; - } - if (String(row.displayName).toUpperCase().includes(value)) { - return true; - } - return false; - case 'VideoPlay': - if (String(row.displayName).toUpperCase().includes(value)) { - return true; - } - if (String(row.videoName).toUpperCase().includes(value)) { - return true; - } - if (String(row.videoUrl).toUpperCase().includes(value)) { - return true; - } - return false; - case 'StringLoad': - case 'ImageLoad': - if (String(row.resourceUrl).toUpperCase().includes(value)) { - return true; - } - return false; - } - return true; - }, - - gameLogIsFriend(row) { - if (typeof row.isFriend !== 'undefined') { - return row.isFriend; - } - if (!row.userId) { - return false; - } - row.isFriend = this.friends.has(row.userId); - return row.isFriend; - }, - - gameLogIsFavorite(row) { - if (typeof row.isFavorite !== 'undefined') { - return row.isFavorite; - } - if (!row.userId) { - return false; - } - row.isFavorite = this.localFavoriteFriends.has(row.userId); - return row.isFavorite; - }, - - async disableGameLogDialog() { - this.gameLogDisabled = !this.gameLogDisabled; - if (this.isGameRunning) { - this.$message({ - message: - 'VRChat needs to be closed before this option can be changed', - type: 'error' - }); - this.gameLogDisabled = !this.gameLogDisabled; - return; - } - if (this.gameLogDisabled) { - this.$confirm('Continue? Disable GameLog', 'Confirm', { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - callback: async (action) => { - if (action !== 'confirm') { - this.gameLogDisabled = !this.gameLogDisabled; - await configRepository.setBool( - 'VRCX_gameLogDisabled', - this.gameLogDisabled - ); - } - } - }); - } else { - await configRepository.setBool( - 'VRCX_gameLogDisabled', - this.gameLogDisabled - ); - } - } - }; -} diff --git a/src/classes/gameRealtimeLogging.js b/src/classes/gameRealtimeLogging.js deleted file mode 100644 index 2b10797a..00000000 --- a/src/classes/gameRealtimeLogging.js +++ /dev/null @@ -1,1451 +0,0 @@ -import * as workerTimers from 'worker-timers'; -import { displayLocation, parseLocation } from '../composables/instance/utils'; -import { checkVRChatCache } from '../composables/shared/utils'; -import configRepository from '../service/config.js'; -import database from '../service/database.js'; -import { baseClass, $app, API, $utils } from './baseClass.js'; -import { instanceRequest, userRequest } from '../api'; -import { - photonEmojis, - photonEventType -} from '../composables/shared/constants/photon.js'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - _data = { - photonLoggingEnabled: false, - moderationEventQueue: new Map(), - moderationAgainstTable: [], - photonLobby: new Map(), - photonLobbyMaster: 0, - photonLobbyCurrentUser: 0, - photonLobbyUserData: new Map(), - photonLobbyCurrent: new Map(), - photonLobbyAvatars: new Map(), - photonLobbyLastModeration: new Map(), - photonLobbyWatcherLoop: false, - photonLobbyTimeout: [], - photonLobbyJointime: new Map(), - photonLobbyActivePortals: new Map(), - photonEvent7List: new Map(), - photonLastEvent7List: '', - photonLastChatBoxMsg: new Map(), - - photonEventTable: { - data: [], - filters: [ - { - prop: ['displayName', 'text'], - value: '' - }, - { - prop: 'type', - value: [], - filterFn: (row, filter) => - filter.value.some((v) => v === row.type) - } - ], - tableProps: { - stripe: true, - size: 'mini' - }, - pageSize: 10, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [5, 10, 15, 25, 50] - } - }, - - photonEventTablePrevious: { - data: [], - filters: [ - { - prop: ['displayName', 'text'], - value: '' - }, - { - prop: 'type', - value: [], - filterFn: (row, filter) => - filter.value.some((v) => v === row.type) - } - ], - tableProps: { - stripe: true, - size: 'mini' - }, - pageSize: 10, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [5, 10, 15, 25, 50] - } - }, - - photonEventTableFilter: '', - photonEventTableTypeFilter: [], - photonEventTableTypeOverlayFilter: [], - photonEventTableTypeFilterList: [ - 'Event', - 'OnPlayerJoined', - 'OnPlayerLeft', - 'ChangeAvatar', - 'ChangeStatus', - 'ChangeGroup', - 'PortalSpawn', - 'DeletedPortal', - 'ChatBoxMessage', - 'Moderation', - 'Camera', - 'SpawnEmoji', - 'MasterMigrate' - ] - }; - - _methods = { - startLobbyWatcherLoop() { - if (!this.photonLobbyWatcherLoop) { - this.photonLobbyWatcherLoop = true; - this.photonLobbyWatcher(); - } - }, - - photonLobbyWatcherLoopStop() { - this.photonLobbyWatcherLoop = false; - this.photonLobbyTimeout = []; - AppApi.ExecuteVrOverlayFunction('updateHudTimeout', '[]'); - }, - - photonLobbyWatcher() { - if (!this.photonLobbyWatcherLoop) { - return; - } - if (this.photonLobbyCurrent.size === 0) { - this.photonLobbyWatcherLoopStop(); - return; - } - var dtNow = Date.now(); - var bias2 = this.photonLastEvent7List + 1.5 * 1000; - if (dtNow > bias2 || this.lastLocation.playerList.size <= 1) { - if (this.photonLobbyTimeout.length > 0) { - AppApi.ExecuteVrOverlayFunction('updateHudTimeout', '[]'); - } - this.photonLobbyTimeout = []; - workerTimers.setTimeout(() => this.photonLobbyWatcher(), 500); - return; - } - var hudTimeout = []; - this.photonEvent7List.forEach((dt, id) => { - var timeSinceLastEvent = dtNow - Date.parse(dt); - if ( - timeSinceLastEvent > this.photonLobbyTimeoutThreshold && - id !== this.photonLobbyCurrentUser - ) { - if (this.photonLobbyJointime.has(id)) { - var { joinTime } = this.photonLobbyJointime.get(id); - } - if (!joinTime) { - console.log(`${id} missing join time`); - } - if (joinTime && joinTime + 70000 < dtNow) { - // wait 70secs for user to load in - hudTimeout.unshift({ - userId: this.getUserIdFromPhotonId(id), - displayName: this.getDisplayNameFromPhotonId(id), - time: Math.round(timeSinceLastEvent / 1000), - rawTime: timeSinceLastEvent - }); - } - } - }); - if (this.photonLobbyTimeout.length > 0 || hudTimeout.length > 0) { - hudTimeout.sort(function (a, b) { - if (a.rawTime > b.rawTime) { - return 1; - } - if (a.rawTime < b.rawTime) { - return -1; - } - return 0; - }); - if (this.timeoutHudOverlay) { - if ( - this.timeoutHudOverlayFilter === 'VIP' || - this.timeoutHudOverlayFilter === 'Friends' - ) { - var filteredHudTimeout = []; - hudTimeout.forEach((item) => { - if ( - this.timeoutHudOverlayFilter === 'VIP' && - API.cachedFavoritesByObjectId.has(item.userId) - ) { - filteredHudTimeout.push(item); - } else if ( - this.timeoutHudOverlayFilter === 'Friends' && - this.friends.has(item.userId) - ) { - filteredHudTimeout.push(item); - } - }); - } else { - var filteredHudTimeout = hudTimeout; - } - AppApi.ExecuteVrOverlayFunction( - 'updateHudTimeout', - JSON.stringify(filteredHudTimeout) - ); - } - this.photonLobbyTimeout = hudTimeout; - this.getCurrentInstanceUserList(); - } - workerTimers.setTimeout(() => this.photonLobbyWatcher(), 500); - }, - - addEntryPhotonEvent(input) { - var isMaster = false; - if (input.photonId === this.photonLobbyMaster) { - isMaster = true; - } - var joinTimeRef = this.photonLobbyJointime.get(input.photonId); - var isModerator = joinTimeRef?.canModerateInstance; - var photonUserRef = this.photonLobby.get(input.photonId); - var displayName = ''; - var userId = ''; - var isFriend = false; - if (typeof photonUserRef !== 'undefined') { - displayName = photonUserRef.displayName; - userId = photonUserRef.id; - isFriend = photonUserRef.isFriend; - } - var isFavorite = this.localFavoriteFriends.has(userId); - var colour = ''; - var tagRef = this.customUserTags.get(userId); - if (typeof tagRef !== 'undefined') { - colour = tagRef.colour; - } - var feed = { - displayName, - userId, - isFavorite, - isFriend, - isMaster, - isModerator, - colour, - ...input - }; - this.photonEventTable.data.unshift(feed); - if ( - this.photonEventTableTypeOverlayFilter.length > 0 && - !this.photonEventTableTypeOverlayFilter.includes(feed.type) - ) { - return; - } - if (this.photonEventOverlay) { - if ( - this.photonEventOverlayFilter === 'VIP' || - this.photonEventOverlayFilter === 'Friends' - ) { - if ( - feed.userId && - ((this.photonEventOverlayFilter === 'VIP' && - isFavorite) || - (this.photonEventOverlayFilter === 'Friends' && - isFriend)) - ) { - AppApi.ExecuteVrOverlayFunction( - 'addEntryHudFeed', - JSON.stringify(feed) - ); - } - } else { - AppApi.ExecuteVrOverlayFunction( - 'addEntryHudFeed', - JSON.stringify(feed) - ); - } - } - }, - - getDisplayNameFromPhotonId(photonId) { - var displayName = ''; - if (photonId) { - var ref = this.photonLobby.get(photonId); - displayName = `ID:${photonId}`; - if ( - typeof ref !== 'undefined' && - typeof ref.displayName !== 'undefined' - ) { - displayName = ref.displayName; - } - } - return displayName; - }, - - getUserIdFromPhotonId(photonId) { - var userId = ''; - if (photonId) { - var ref = this.photonLobby.get(photonId); - if ( - typeof ref !== 'undefined' && - typeof ref.id !== 'undefined' - ) { - userId = ref.id; - } - } - return userId; - }, - - showUserFromPhotonId(photonId) { - if (photonId) { - var ref = this.photonLobby.get(photonId); - if (typeof ref !== 'undefined') { - if (typeof ref.id !== 'undefined') { - this.showUserDialog(ref.id); - } else if (typeof ref.displayName !== 'undefined') { - this.lookupUser(ref); - } - } else { - this.$message({ - message: 'No user info available', - type: 'error' - }); - } - } - }, - - getPhotonIdFromDisplayName(displayName) { - var photonId = ''; - if (displayName) { - this.photonLobby.forEach((ref, id) => { - if ( - typeof ref !== 'undefined' && - ref.displayName === displayName - ) { - photonId = id; - } - }); - } - return photonId; - }, - - getPhotonIdFromUserId(userId) { - var photonId = ''; - if (userId) { - this.photonLobby.forEach((ref, id) => { - if (typeof ref !== 'undefined' && ref.id === userId) { - photonId = id; - } - }); - } - return photonId; - }, - - sortPhotonId(a, b, field) { - var id1 = this.getPhotonIdFromDisplayName(a[field]); - var id2 = this.getPhotonIdFromDisplayName(b[field]); - if (id1 < id2) { - return 1; - } - if (id1 > id2) { - return -1; - } - return 0; - }, - - parsePhotonEvent(data, gameLogDate) { - switch (data.Code) { - case 253: - // SetUserProperties - if (data.Parameters[253] === -1) { - for (var i in data.Parameters[251]) { - var id = parseInt(i, 10); - var user = data.Parameters[251][i]; - this.parsePhotonUser(id, user.user, gameLogDate); - this.parsePhotonAvatarChange( - id, - user.user, - user.avatarDict, - gameLogDate - ); - this.parsePhotonGroupChange( - id, - user.user, - user.groupOnNameplate, - gameLogDate - ); - this.parsePhotonAvatar(user.avatarDict); - this.parsePhotonAvatar(user.favatarDict); - var hasInstantiated = false; - var lobbyJointime = - this.photonLobbyJointime.get(id); - if (typeof lobbyJointime !== 'undefined') { - hasInstantiated = lobbyJointime.hasInstantiated; - } - this.photonLobbyJointime.set(id, { - joinTime: Date.parse(gameLogDate), - hasInstantiated, - inVRMode: user.inVRMode, - avatarEyeHeight: user.avatarEyeHeight, - canModerateInstance: user.canModerateInstance, - groupOnNameplate: user.groupOnNameplate, - showGroupBadgeToOthers: - user.showGroupBadgeToOthers, - showSocialRank: user.showSocialRank, - useImpostorAsFallback: - user.useImpostorAsFallback, - platform: user.platform - }); - this.photonUserJoin(id, user, gameLogDate); - } - } else { - console.log('oldSetUserProps', data); - var id = parseInt(data.Parameters[253], 10); - var user = data.Parameters[251]; - this.parsePhotonUser(id, user.user, gameLogDate); - this.parsePhotonAvatarChange( - id, - user.user, - user.avatarDict, - gameLogDate - ); - this.parsePhotonGroupChange( - id, - user.user, - user.groupOnNameplate, - gameLogDate - ); - this.parsePhotonAvatar(user.avatarDict); - this.parsePhotonAvatar(user.favatarDict); - var hasInstantiated = false; - var lobbyJointime = this.photonLobbyJointime.get(id); - if (typeof lobbyJointime !== 'undefined') { - hasInstantiated = lobbyJointime.hasInstantiated; - } - this.photonLobbyJointime.set(id, { - joinTime: Date.parse(gameLogDate), - hasInstantiated, - inVRMode: user.inVRMode, - avatarEyeHeight: user.avatarEyeHeight, - canModerateInstance: user.canModerateInstance, - groupOnNameplate: user.groupOnNameplate, - showGroupBadgeToOthers: user.showGroupBadgeToOthers, - showSocialRank: user.showSocialRank, - useImpostorAsFallback: user.useImpostorAsFallback, - platform: user.platform - }); - this.photonUserJoin(id, user, gameLogDate); - } - break; - case 42: - // SetUserProperties - var id = parseInt(data.Parameters[254], 10); - var user = data.Parameters[245]; - this.parsePhotonUser(id, user.user, gameLogDate); - this.parsePhotonAvatarChange( - id, - user.user, - user.avatarDict, - gameLogDate - ); - this.parsePhotonGroupChange( - id, - user.user, - user.groupOnNameplate, - gameLogDate - ); - this.parsePhotonAvatar(user.avatarDict); - this.parsePhotonAvatar(user.favatarDict); - var lobbyJointime = this.photonLobbyJointime.get(id); - this.photonLobbyJointime.set(id, { - hasInstantiated: true, - ...lobbyJointime, - inVRMode: user.inVRMode, - avatarEyeHeight: user.avatarEyeHeight, - canModerateInstance: user.canModerateInstance, - groupOnNameplate: user.groupOnNameplate, - showGroupBadgeToOthers: user.showGroupBadgeToOthers, - showSocialRank: user.showSocialRank, - useImpostorAsFallback: user.useImpostorAsFallback, - platform: user.platform - }); - break; - case 255: - // Join - if (typeof data.Parameters[249] !== 'undefined') { - this.parsePhotonUser( - data.Parameters[254], - data.Parameters[249].user, - gameLogDate - ); - this.parsePhotonAvatarChange( - data.Parameters[254], - data.Parameters[249].user, - data.Parameters[249].avatarDict, - gameLogDate - ); - this.parsePhotonGroupChange( - data.Parameters[254], - data.Parameters[249].user, - data.Parameters[249].groupOnNameplate, - gameLogDate - ); - this.parsePhotonAvatar(data.Parameters[249].avatarDict); - this.parsePhotonAvatar( - data.Parameters[249].favatarDict - ); - } - this.parsePhotonLobbyIds(data.Parameters[252]); - var hasInstantiated = false; - if (this.photonLobbyCurrentUser === data.Parameters[254]) { - // fix current user - hasInstantiated = true; - } - var ref = this.photonLobbyCurrent.get(data.Parameters[254]); - if (typeof ref !== 'undefined') { - // fix for join event firing twice - // fix instantiation happening out of order before join event - hasInstantiated = ref.hasInstantiated; - } - this.photonLobbyJointime.set(data.Parameters[254], { - joinTime: Date.parse(gameLogDate), - hasInstantiated, - inVRMode: data.Parameters[249].inVRMode, - avatarEyeHeight: data.Parameters[249].avatarEyeHeight, - canModerateInstance: - data.Parameters[249].canModerateInstance, - groupOnNameplate: data.Parameters[249].groupOnNameplate, - showGroupBadgeToOthers: - data.Parameters[249].showGroupBadgeToOthers, - showSocialRank: data.Parameters[249].showSocialRank, - useImpostorAsFallback: - data.Parameters[249].useImpostorAsFallback, - platform: data.Parameters[249].platform - }); - this.photonUserJoin( - data.Parameters[254], - data.Parameters[249], - gameLogDate - ); - this.startLobbyWatcherLoop(); - break; - case 254: - // Leave - var photonId = data.Parameters[254]; - this.photonUserLeave(photonId, gameLogDate); - this.photonLobbyCurrent.delete(photonId); - this.photonLobbyLastModeration.delete(photonId); - this.photonLobbyJointime.delete(photonId); - this.photonEvent7List.delete(photonId); - this.parsePhotonLobbyIds(data.Parameters[252]); - if (typeof data.Parameters[203] !== 'undefined') { - this.setPhotonLobbyMaster( - data.Parameters[203], - gameLogDate - ); - } - break; - case 4: - // Sync - this.setPhotonLobbyMaster( - data.Parameters[254], - gameLogDate - ); - break; - case 33: - // Moderation - if (data.Parameters[245]['0'] === 21) { - if (data.Parameters[245]['1']) { - var photonId = data.Parameters[245]['1']; - var block = data.Parameters[245]['10']; - var mute = data.Parameters[245]['11']; - var ref = this.photonLobby.get(photonId); - if ( - typeof ref !== 'undefined' && - typeof ref.id !== 'undefined' - ) { - this.photonModerationUpdate( - ref, - photonId, - block, - mute, - gameLogDate - ); - } else { - this.moderationEventQueue.set(photonId, { - block, - mute, - gameLogDate - }); - } - } else { - var blockArray = data.Parameters[245]['10']; - var muteArray = data.Parameters[245]['11']; - var idList = new Map(); - blockArray.forEach((photonId1) => { - if (muteArray.includes(photonId1)) { - idList.set(photonId1, { - isMute: true, - isBlock: true - }); - } else { - idList.set(photonId1, { - isMute: false, - isBlock: true - }); - } - }); - muteArray.forEach((photonId2) => { - if (!idList.has(photonId2)) { - idList.set(photonId2, { - isMute: true, - isBlock: false - }); - } - }); - idList.forEach(({ isMute, isBlock }, photonId3) => { - var ref1 = this.photonLobby.get(photonId3); - if ( - typeof ref1 !== 'undefined' && - typeof ref1.id !== 'undefined' - ) { - this.photonModerationUpdate( - ref1, - photonId3, - isBlock, - isMute, - gameLogDate - ); - } else { - this.moderationEventQueue.set(photonId3, { - block: isBlock, - mute: isMute, - gameLogDate - }); - } - }); - } - } else if ( - data.Parameters[245]['0'] === 13 || - data.Parameters[245]['0'] === 25 - ) { - var msg = data.Parameters[245]['2']; - if ( - typeof msg === 'string' && - typeof data.Parameters[245]['14'] === 'object' - ) { - for (var prop in data.Parameters[245]['14']) { - var value = data.Parameters[245]['14'][prop]; - msg = msg.replace(`{{${prop}}}`, value); - } - } - this.addEntryPhotonEvent({ - photonId, - text: msg, - type: 'Moderation', - color: 'yellow', - created_at: gameLogDate - }); - } - break; - case 202: - // Instantiate - if (!this.photonLobby.has(data.Parameters[254])) { - this.photonLobby.set(data.Parameters[254]); - } - if (!this.photonLobbyCurrent.has(data.Parameters[254])) { - this.photonLobbyCurrent.set(data.Parameters[254]); - } - var lobbyJointime = this.photonLobbyJointime.get( - data.Parameters[254] - ); - if (typeof lobbyJointime !== 'undefined') { - this.photonLobbyJointime.set(data.Parameters[254], { - ...lobbyJointime, - hasInstantiated: true - }); - } else { - this.photonLobbyJointime.set(data.Parameters[254], { - joinTime: Date.parse(gameLogDate), - hasInstantiated: true - }); - } - break; - case 43: - // Chatbox Message - var photonId = data.Parameters[254]; - var text = data.Parameters[245]; - if (this.photonLobbyCurrentUser === photonId) { - return; - } - var lastMsg = this.photonLastChatBoxMsg.get(photonId); - if (lastMsg === text) { - return; - } - this.photonLastChatBoxMsg.set(photonId, text); - var userId = this.getUserIdFromPhotonId(photonId); - if ( - this.chatboxUserBlacklist.has(userId) || - this.checkChatboxBlacklist(text) - ) { - return; - } - this.addEntryPhotonEvent({ - photonId, - text, - type: 'ChatBoxMessage', - created_at: gameLogDate - }); - var entry = { - userId, - displayName: this.getDisplayNameFromPhotonId(photonId), - created_at: gameLogDate, - type: 'ChatBoxMessage', - text - }; - this.queueGameLogNoty(entry); - this.addGameLog(entry); - break; - case 70: - // Portal Spawn - if (data.Parameters[245][0] === 20) { - var portalId = data.Parameters[245][1]; - var userId = data.Parameters[245][2]; - var shortName = data.Parameters[245][5]; - var worldName = data.Parameters[245][8].name; - this.addPhotonPortalSpawn( - gameLogDate, - userId, - shortName, - worldName - ); - this.photonLobbyActivePortals.set(portalId, { - userId, - shortName, - worldName, - created_at: Date.parse(gameLogDate), - playerCount: 0, - pendingLeave: 0 - }); - } else if (data.Parameters[245][0] === 21) { - var portalId = data.Parameters[245][1]; - var userId = data.Parameters[245][2]; - var playerCount = data.Parameters[245][3]; - var shortName = data.Parameters[245][5]; - var worldName = ''; - this.addPhotonPortalSpawn( - gameLogDate, - userId, - shortName, - worldName - ); - this.photonLobbyActivePortals.set(portalId, { - userId, - shortName, - worldName, - created_at: Date.parse(gameLogDate), - playerCount: 0, - pendingLeave: 0 - }); - } else if (data.Parameters[245][0] === 22) { - var portalId = data.Parameters[245][1]; - var text = 'DeletedPortal'; - var ref = this.photonLobbyActivePortals.get(portalId); - if (typeof ref !== 'undefined') { - var worldName = ref.worldName; - var playerCount = ref.playerCount; - var time = $app.timeToText( - Date.parse(gameLogDate) - ref.created_at - ); - text = `DeletedPortal after ${time} with ${playerCount} players to "${worldName}"`; - } - this.addEntryPhotonEvent({ - text, - type: 'DeletedPortal', - created_at: gameLogDate - }); - this.photonLobbyActivePortals.delete(portalId); - } else if (data.Parameters[245][0] === 23) { - var portalId = data.Parameters[245][1]; - var playerCount = data.Parameters[245][3]; - var ref = this.photonLobbyActivePortals.get(portalId); - if (typeof ref !== 'undefined') { - ref.pendingLeave++; - ref.playerCount = playerCount; - } - } else if (data.Parameters[245][0] === 24) { - this.addEntryPhotonEvent({ - text: 'PortalError failed to create portal', - type: 'DeletedPortal', - created_at: gameLogDate - }); - } - break; - case 71: - // Spawn Emoji - var photonId = data.Parameters[254]; - if (photonId === this.photonLobbyCurrentUser) { - return; - } - var type = data.Parameters[245][0]; - var emojiName = ''; - var imageUrl = ''; - if (type === 0) { - var emojiId = data.Parameters[245][2]; - emojiName = photonEmojis[emojiId]; - } else if (type === 1) { - emojiName = 'Custom'; - var fileId = data.Parameters[245][1]; - imageUrl = `https://api.vrchat.cloud/api/1/file/${fileId}/1/`; - } - this.addEntryPhotonEvent({ - photonId, - text: emojiName, - type: 'SpawnEmoji', - created_at: gameLogDate, - imageUrl, - fileId - }); - break; - } - }, - - parseVRCEvent(json) { - // VRC Event - var datetime = json.dt; - var eventData = json.VRCEventData; - var senderId = eventData.Sender; - if (this.debugPhotonLogging) { - console.log('VrcEvent:', json); - } - if (eventData.EventName === '_SendOnSpawn') { - return; - } else if (eventData.EventType > 34) { - var entry = { - created_at: datetime, - type: 'Event', - data: `${this.getDisplayNameFromPhotonId( - senderId - )} called non existent RPC ${eventData.EventType}` - }; - this.addPhotonEventToGameLog(entry); - return; - } - if (eventData.EventType === 14) { - var type = 'Event'; - if (eventData.EventName === 'ChangeVisibility') { - if (eventData.Data[0] === true) { - var text = 'EnableCamera'; - } else if (eventData.Data[0] === false) { - var text = 'DisableCamera'; - } - type = 'Camera'; - } else if (eventData.EventName === 'PhotoCapture') { - var text = 'PhotoCapture'; - type = 'Camera'; - } else if (eventData.EventName === 'TimerBloop') { - var text = 'TimerBloop'; - type = 'Camera'; - } else if (eventData.EventName === 'ReloadAvatarNetworkedRPC') { - var text = 'AvatarReset'; - } else if (eventData.EventName === 'ReleaseBones') { - var text = 'ResetPhysBones'; - } else if (eventData.EventName === 'SpawnEmojiRPC') { - var text = this.oldPhotonEmojis[eventData.Data]; - type = 'SpawnEmoji'; - } else { - var eventVrc = ''; - if (eventData.Data && eventData.Data.length > 0) { - eventVrc = ` ${JSON.stringify(eventData.Data).replace( - /"([^(")"]+)":/g, - '$1:' - )}`; - } - var text = `${eventData.EventName}${eventVrc}`; - } - this.addEntryPhotonEvent({ - photonId: senderId, - text, - type, - created_at: datetime - }); - } else { - var eventName = ''; - if (eventData.EventName) { - eventName = ` ${JSON.stringify(eventData.EventName).replace( - /"([^(")"]+)":/g, - '$1:' - )}`; - } - if (this.debugPhotonLogging) { - var displayName = this.getDisplayNameFromPhotonId(senderId); - var feed = `RPC ${displayName} ${ - photonEventType[eventData.EventType] - }${eventName}`; - console.log('VrcRpc:', feed); - } - } - }, - - async parsePhotonPortalSpawn( - created_at, - instanceId, - ref, - portalType, - shortName, - photonId - ) { - var worldName = shortName; - if (instanceId) { - worldName = await this.getWorldName(instanceId); - } - this.addEntryPhotonEvent({ - photonId, - text: `${portalType} PortalSpawn to ${worldName}`, - type: 'PortalSpawn', - shortName, - location: instanceId, - worldName, - created_at - }); - this.addPhotonEventToGameLog({ - created_at, - type: 'PortalSpawn', - displayName: ref.displayName, - location: this.lastLocation.location, - userId: ref.id, - instanceId, - worldName - }); - }, - - async addPhotonPortalSpawn(gameLogDate, userId, shortName, worldName) { - var instance = await instanceRequest.getInstanceFromShortName({ - shortName - }); - var location = instance.json.location; - var L = parseLocation(location); - var groupName = ''; - if (L.groupId) { - groupName = await this.getGroupName(L.groupId); - } - if (!worldName) { - // eslint-disable-next-line no-param-reassign - worldName = await this.getWorldName(location); - } - // var newShortName = instance.json.shortName; - // var portalType = 'Secure'; - // if (shortName === newShortName) { - // portalType = 'Unlocked'; - // } - var _displayLocation = displayLocation( - location, - worldName, - groupName - ); - this.addEntryPhotonEvent({ - photonId: this.getPhotonIdFromUserId(userId), - text: `PortalSpawn to ${_displayLocation}`, - type: 'PortalSpawn', - shortName, - location, - worldName, - groupName, - created_at: gameLogDate - }); - this.addPhotonEventToGameLog({ - created_at: gameLogDate, - type: 'PortalSpawn', - displayName: this.getDisplayName(userId), - location: this.lastLocation.location, - userId, - instanceId: location, - worldName, - groupName - }); - }, - - addPhotonEventToGameLog(entry) { - this.queueGameLogNoty(entry); - this.addGameLog(entry); - if (entry.type === 'PortalSpawn') { - database.addGamelogPortalSpawnToDatabase(entry); - } else if (entry.type === 'Event') { - database.addGamelogEventToDatabase(entry); - } - }, - - parsePhotonLobbyIds(lobbyIds) { - lobbyIds.forEach((id) => { - if (!this.photonLobby.has(id)) { - this.photonLobby.set(id); - } - if (!this.photonLobbyCurrent.has(id)) { - this.photonLobbyCurrent.set(id); - } - }); - for (var id of this.photonLobbyCurrent.keys()) { - if (!lobbyIds.includes(id)) { - this.photonLobbyCurrent.delete(id); - this.photonEvent7List.delete(id); - } - } - }, - - setPhotonLobbyMaster(photonId, gameLogDate) { - if (this.photonLobbyMaster !== photonId) { - if (this.photonLobbyMaster !== 0) { - this.addEntryPhotonEvent({ - photonId, - text: `Photon Master Migrate`, - type: 'MasterMigrate', - created_at: gameLogDate - }); - } - this.photonLobbyMaster = photonId; - } - }, - - async parsePhotonUser(photonId, user, gameLogDate) { - if (typeof user === 'undefined') { - console.error('PhotonUser: user is undefined', photonId); - return; - } - var tags = []; - if (typeof user.tags !== 'undefined') { - tags = user.tags; - } - var ref = API.cachedUsers.get(user.id); - var photonUser = { - id: user.id, - displayName: user.displayName, - developerType: user.developerType, - profilePicOverride: user.profilePicOverride, - currentAvatarImageUrl: user.currentAvatarImageUrl, - currentAvatarThumbnailImageUrl: - user.currentAvatarThumbnailImageUrl, - userIcon: user.userIcon, - last_platform: user.last_platform, - allowAvatarCopying: user.allowAvatarCopying, - status: user.status, - statusDescription: user.statusDescription, - bio: user.bio, - tags - }; - this.photonLobby.set(photonId, photonUser); - this.photonLobbyCurrent.set(photonId, photonUser); - this.photonLobbyUserDataUpdate(photonId, photonUser, gameLogDate); - - var bias = Date.parse(gameLogDate) + 60 * 1000; // 1min - if (bias > Date.now()) { - if ( - typeof ref === 'undefined' || - typeof ref.id === 'undefined' - ) { - try { - var args = await userRequest.getUser({ - userId: user.id - }); - ref = args.ref; - } catch (err) { - console.error(err); - ref = photonUser; - } - } else if ( - !ref.isFriend && - this.lastLocation.playerList.has(user.id) - ) { - var { joinTime } = this.lastLocation.playerList.get( - user.id - ); - if (!joinTime) { - joinTime = Date.parse(gameLogDate); - } - ref.$location_at = joinTime; - ref.$online_for = joinTime; - } - if ( - typeof ref.id !== 'undefined' && - ref.currentAvatarImageUrl !== user.currentAvatarImageUrl - ) { - API.applyUser({ - ...ref, - currentAvatarImageUrl: user.currentAvatarImageUrl, - currentAvatarThumbnailImageUrl: - user.currentAvatarThumbnailImageUrl - }); - } - } - if (typeof ref !== 'undefined' && typeof ref.id !== 'undefined') { - this.photonLobby.set(photonId, ref); - this.photonLobbyCurrent.set(photonId, ref); - // check moderation queue - if (this.moderationEventQueue.has(photonId)) { - var { block, mute, gameLogDate } = - this.moderationEventQueue.get(photonId); - this.moderationEventQueue.delete(photonId); - this.photonModerationUpdate( - ref, - photonId, - block, - mute, - gameLogDate - ); - } - } - }, - - photonLobbyUserDataUpdate(photonId, photonUser, gameLogDate) { - var ref = this.photonLobbyUserData.get(photonId); - if ( - typeof ref !== 'undefined' && - photonId !== this.photonLobbyCurrentUser && - (photonUser.status !== ref.status || - photonUser.statusDescription !== ref.statusDescription) - ) { - this.addEntryPhotonEvent({ - photonId, - type: 'ChangeStatus', - status: photonUser.status, - previousStatus: ref.status, - statusDescription: $utils.replaceBioSymbols( - photonUser.statusDescription - ), - previousStatusDescription: $utils.replaceBioSymbols( - ref.statusDescription - ), - created_at: Date.parse(gameLogDate) - }); - } - this.photonLobbyUserData.set(photonId, photonUser); - }, - - photonUserJoin(photonId, user, gameLogDate) { - if (photonId === this.photonLobbyCurrentUser) { - return; - } - var avatar = user.avatarDict; - avatar.name = $utils.replaceBioSymbols(avatar.name); - avatar.description = $utils.replaceBioSymbols(avatar.description); - var platform = ''; - if (user.last_platform === 'android') { - platform = 'Android'; - } else if (user.last_platform === 'ios') { - platform = 'iOS'; - } else if (user.inVRMode) { - platform = 'VR'; - } else { - platform = 'Desktop'; - } - this.photonUserSusieCheck(photonId, user, gameLogDate); - checkVRChatCache(avatar).then((cacheInfo) => { - var inCache = false; - if (cacheInfo.Item1 > 0) { - inCache = true; - } - this.addEntryPhotonEvent({ - photonId, - text: 'has joined', - type: 'OnPlayerJoined', - created_at: gameLogDate, - avatar, - inCache, - platform - }); - }); - }, - - photonUserSusieCheck(photonId, user, gameLogDate) { - var text = ''; - if (typeof user.modTag !== 'undefined') { - text = `Moderator has joined ${user.modTag}`; - } else if (user.isInvisible) { - text = 'User joined invisible'; - } - if (text) { - this.addEntryPhotonEvent({ - photonId, - text, - type: 'Event', - color: 'yellow', - created_at: gameLogDate - }); - var entry = { - created_at: new Date().toJSON(), - type: 'Event', - data: `${text} - ${this.getDisplayNameFromPhotonId( - photonId - )} (${this.getUserIdFromPhotonId(photonId)})` - }; - this.queueGameLogNoty(entry); - this.addGameLog(entry); - database.addGamelogEventToDatabase(entry); - } - }, - - photonUserLeave(photonId, gameLogDate) { - if (!this.photonLobbyCurrent.has(photonId)) { - return; - } - var text = 'has left'; - var lastEvent = this.photonEvent7List.get(parseInt(photonId, 10)); - if (typeof lastEvent !== 'undefined') { - var timeSinceLastEvent = Date.now() - Date.parse(lastEvent); - if (timeSinceLastEvent > 10 * 1000) { - // 10 seconds - text = `has timed out after ${$app.timeToText(timeSinceLastEvent)}`; - } - } - this.photonLobbyActivePortals.forEach((portal) => { - if (portal.pendingLeave > 0) { - text = `has left through portal to "${portal.worldName}"`; - portal.pendingLeave--; - } - }); - this.addEntryPhotonEvent({ - photonId, - text, - type: 'OnPlayerLeft', - created_at: gameLogDate - }); - }, - - photonModerationUpdate(ref, photonId, block, mute, gameLogDate) { - database.getModeration(ref.id).then((row) => { - var lastType = this.photonLobbyLastModeration.get(photonId); - var type = ''; - var text = ''; - if (block) { - type = 'Blocked'; - text = 'Blocked'; - } else if (mute) { - type = 'Muted'; - text = 'Muted'; - } - if (row.userId) { - if (!block && row.block) { - type = 'Unblocked'; - text = 'Unblocked'; - } else if (!mute && row.mute) { - type = 'Unmuted'; - text = 'Unmuted'; - } - if (block === row.block && mute === row.mute) { - // no change - if (type && type !== lastType) { - this.addEntryPhotonEvent({ - photonId, - text: `Moderation ${text}`, - type: 'Moderation', - color: 'yellow', - created_at: gameLogDate - }); - } - this.photonLobbyLastModeration.set(photonId, type); - return; - } - } - this.photonLobbyLastModeration.set(photonId, type); - this.moderationAgainstTable.forEach((item) => { - if (item.userId === ref.id && item.type === type) { - $app.removeFromArray(this.moderationAgainstTable, item); - } - }); - if (type) { - this.addEntryPhotonEvent({ - photonId, - text: `Moderation ${text}`, - type: 'Moderation', - color: 'yellow', - created_at: gameLogDate - }); - var noty = { - created_at: new Date().toJSON(), - userId: ref.id, - displayName: ref.displayName, - type - }; - this.queueModerationNoty(noty); - var entry = { - created_at: gameLogDate, - userId: ref.id, - displayName: ref.displayName, - type - }; - this.moderationAgainstTable.push(entry); - } - if (block || mute || block !== row.block || mute !== row.mute) { - this.updateSharedFeed(true); - } - if (block || mute) { - database.setModeration({ - userId: ref.id, - updatedAt: gameLogDate, - displayName: ref.displayName, - block, - mute - }); - } else if (row.block || row.mute) { - database.deleteModeration(ref.id); - } - }); - }, - - parsePhotonAvatarChange(photonId, user, avatar, gameLogDate) { - if (typeof avatar === 'undefined') { - return; - } - if (typeof user === 'undefined') { - console.error( - 'PhotonAvatarChange: user is undefined', - photonId - ); - return; - } - var oldAvatarId = this.photonLobbyAvatars.get(user.id); - if ( - oldAvatarId && - oldAvatarId !== avatar.id && - photonId !== this.photonLobbyCurrentUser - ) { - avatar.name = $utils.replaceBioSymbols(avatar.name); - avatar.description = $utils.replaceBioSymbols( - avatar.description - ); - checkVRChatCache(avatar).then((cacheInfo) => { - var inCache = false; - if (cacheInfo.Item1 > 0) { - inCache = true; - } - var entry = { - created_at: new Date().toJSON(), - type: 'AvatarChange', - userId: user.id, - displayName: user.displayName, - name: avatar.name, - description: avatar.description, - avatarId: avatar.id, - authorId: avatar.authorId, - releaseStatus: avatar.releaseStatus, - imageUrl: avatar.imageUrl, - thumbnailImageUrl: avatar.thumbnailImageUrl - }; - this.queueGameLogNoty(entry); - this.addGameLog(entry); - this.addEntryPhotonEvent({ - photonId, - displayName: user.displayName, - userId: user.id, - text: `ChangeAvatar ${avatar.name}`, - type: 'ChangeAvatar', - created_at: gameLogDate, - avatar, - inCache - }); - }); - } - this.photonLobbyAvatars.set(user.id, avatar.id); - }, - - async parsePhotonGroupChange(photonId, user, groupId, gameLogDate) { - if ( - typeof user === 'undefined' || - !this.photonLobbyJointime.has(photonId) - ) { - return; - } - var { groupOnNameplate } = this.photonLobbyJointime.get(photonId); - if ( - typeof groupOnNameplate !== 'undefined' && - groupOnNameplate !== groupId && - photonId !== this.photonLobbyCurrentUser - ) { - var groupName = await this.getGroupName(groupId); - var previousGroupName = - await this.getGroupName(groupOnNameplate); - this.addEntryPhotonEvent({ - photonId, - displayName: user.displayName, - userId: user.id, - text: `ChangeGroup ${groupName}`, - type: 'ChangeGroup', - created_at: gameLogDate, - groupId, - groupName, - previousGroupId: groupOnNameplate, - previousGroupName - }); - } - }, - - parsePhotonAvatar(avatar) { - if ( - typeof avatar === 'undefined' || - typeof avatar.id === 'undefined' - ) { - console.error('PhotonAvatar: avatar is undefined'); - return; - } - var tags = []; - var unityPackages = []; - if (typeof avatar.tags !== 'undefined') { - tags = avatar.tags; - } - if (typeof avatar.unityPackages !== 'undefined') { - unityPackages = avatar.unityPackages; - } - if (!avatar.assetUrl && unityPackages.length > 0) { - for (var unityPackage of unityPackages) { - if ( - unityPackage.variant && - unityPackage.variant !== 'standard' && - unityPackage.variant !== 'security' - ) { - continue; - } - if (unityPackage.platform === 'standalonewindows') { - avatar.assetUrl = unityPackage.assetUrl; - } - } - } - API.applyAvatar({ - id: avatar.id, - authorId: avatar.authorId, - authorName: avatar.authorName, - updated_at: avatar.updated_at, - description: avatar.description, - imageUrl: avatar.imageUrl, - thumbnailImageUrl: avatar.thumbnailImageUrl, - name: avatar.name, - releaseStatus: avatar.releaseStatus, - version: avatar.version, - tags, - unityPackages - }); - }, - - async photonEventTableFilterChange() { - this.photonEventTable.filters[0].value = - this.photonEventTableFilter; - this.photonEventTable.filters[1].value = - this.photonEventTableTypeFilter; - - this.photonEventTablePrevious.filters[0].value = - this.photonEventTableFilter; - this.photonEventTablePrevious.filters[1].value = - this.photonEventTableTypeFilter; - - await configRepository.setString( - 'VRCX_photonEventTypeFilter', - JSON.stringify(this.photonEventTableTypeFilter) - ); - await configRepository.setString( - 'VRCX_photonEventTypeOverlayFilter', - JSON.stringify(this.photonEventTableTypeOverlayFilter) - ); - } - }; -} diff --git a/src/classes/groups.js b/src/classes/groups.js deleted file mode 100644 index 1af73281..00000000 --- a/src/classes/groups.js +++ /dev/null @@ -1,1057 +0,0 @@ -import * as workerTimers from 'worker-timers'; -import configRepository from '../service/config.js'; -import { baseClass, $app, API, $t } from './baseClass.js'; -import { - userRequest, - worldRequest, - instanceRequest, - groupRequest -} from '../api'; -import $utils from './utils'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - init() { - API.cachedGroups = new Map(); - API.currentUserGroups = new Map(); - - API.$on('GROUP', function (args) { - args.ref = this.applyGroup(args.json); - }); - - API.$on('GROUP', function (args) { - var { ref } = args; - var D = $app.groupDialog; - if (D.visible === false || D.id !== ref.id) { - return; - } - D.inGroup = ref.membershipStatus === 'member'; - D.ref = ref; - }); - - API.$on('GROUP:REPRESENTED', function (args) { - var json = args.json; - if (!json.groupId) { - // no group - return; - } - json.$memberId = json.id; - json.id = json.groupId; - this.$emit('GROUP', { - json, - params: { - groupId: json.groupId, - userId: args.params.userId - } - }); - }); - - API.$on('GROUP:LIST', function (args) { - for (var json of args.json) { - json.$memberId = json.id; - json.id = json.groupId; - this.$emit('GROUP', { - json, - params: { - groupId: json.id, - userId: args.params.userId - } - }); - } - }); - - API.$on('GROUP:MEMBER:PROPS', function (args) { - if (args.userId !== this.currentUser.id) { - return; - } - var json = args.json; - json.$memberId = json.id; - json.id = json.groupId; - if ( - $app.groupDialog.visible && - $app.groupDialog.id === json.groupId - ) { - $app.groupDialog.ref.myMember.visibility = json.visibility; - $app.groupDialog.ref.myMember.isSubscribedToAnnouncements = - json.isSubscribedToAnnouncements; - } - if ( - $app.userDialog.visible && - $app.userDialog.id === this.currentUser.id - ) { - $app.getCurrentUserRepresentedGroup(); - } - this.$emit('GROUP:MEMBER', { - json, - params: { - groupId: json.groupId - } - }); - }); - - API.$on('GROUP:MEMBER:PROPS', function (args) { - if ($app.groupDialog.id === args.json.groupId) { - for (var i = 0; i < $app.groupDialog.members.length; ++i) { - var member = $app.groupDialog.members[i]; - if (member.userId === args.json.userId) { - Object.assign(member, this.applyGroupMember(args.json)); - break; - } - } - for ( - var i = 0; - i < $app.groupDialog.memberSearchResults.length; - ++i - ) { - var member = $app.groupDialog.memberSearchResults[i]; - if (member.userId === args.json.userId) { - Object.assign(member, this.applyGroupMember(args.json)); - break; - } - } - } - - // The 'GROUP:MEMBER:PROPS' event is triggered by the setGroupVisibility, setGroupSubscription, or groupMembersSaveNote. - // The first two methods originate from the Group Dialog (visibility/Subscription); - // Group Member Moderation Dialog is necessarily not visible then. - - // if ( - // $app.groupMemberModeration.visible && - // $app.groupMemberModeration.id === args.json.groupId - // ) { - // // force redraw table - // $app.groupMembersSearch(); - // } - }); - - API.$on('GROUP:PERMISSIONS', function (args) { - if (args.params.userId !== this.currentUser.id) { - return; - } - var json = args.json; - for (var groupId in json) { - var permissions = json[groupId]; - var group = this.cachedGroups.get(groupId); - if (group) { - group.myMember.permissions = permissions; - } - } - }); - - /** - * @param {{ groupId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.getAllGroupPosts = async function (params) { - var posts = []; - var offset = 0; - var n = 100; - var total = 0; - do { - var args = await groupRequest.getGroupPosts({ - groupId: params.groupId, - n, - offset - }); - posts = posts.concat(args.json.posts); - total = args.json.total; - offset += n; - } while (offset < total); - var returnArgs = { - posts, - params - }; - this.$emit('GROUP:POSTS:ALL', returnArgs); - return returnArgs; - }; - - API.$on('GROUP:POSTS:ALL', function (args) { - var D = $app.groupDialog; - if (D.id === args.params.groupId) { - for (var post of args.posts) { - post.title = $utils.replaceBioSymbols(post.title); - post.text = $utils.replaceBioSymbols(post.text); - } - if (args.posts.length > 0) { - D.announcement = args.posts[0]; - } - D.posts = args.posts; - $app.updateGroupPostSearch(); - } - }); - - API.$on('GROUP:POST', function (args) { - var D = $app.groupDialog; - if (D.id !== args.params.groupId) { - return; - } - - var newPost = args.json; - newPost.title = $utils.replaceBioSymbols(newPost.title); - newPost.text = $utils.replaceBioSymbols(newPost.text); - var hasPost = false; - // update existing post - for (var post of D.posts) { - if (post.id === newPost.id) { - Object.assign(post, newPost); - hasPost = true; - break; - } - } - // set or update announcement - if (newPost.id === D.announcement.id || !D.announcement.id) { - D.announcement = newPost; - } - // add new post - if (!hasPost) { - D.posts.unshift(newPost); - } - $app.updateGroupPostSearch(); - }); - - API.$on('GROUP:MEMBERS', function (args) { - for (var json of args.json) { - this.$emit('GROUP:MEMBER', { - json, - params: { - groupId: args.params.groupId - } - }); - } - }); - - API.$on('GROUP:MEMBER', function (args) { - args.ref = this.applyGroupMember(args.json); - }); - - API.$on('GROUP:USER:INSTANCES', function (args) { - $app.groupInstances = []; - for (const json of args.json.instances) { - if (args.json.fetchedAt) { - // tack on fetchedAt - json.$fetchedAt = args.json.fetchedAt; - } - this.$emit('INSTANCE', { - json, - params: { - fetchedAt: args.json.fetchedAt - } - }); - const ref = this.cachedGroups.get(json.ownerId); - if (typeof ref === 'undefined') { - if ($app.friendLogInitStatus) { - groupRequest.getGroup({ groupId: json.ownerId }); - } - return; - } - $app.groupInstances.push({ - group: ref, - instance: this.applyInstance(json) - }); - } - }); - - /** - * @param {{ groupId: string }} params - * @return { Promise<{json: any, params}> } - */ - API.getCachedGroup = function (params) { - return new Promise((resolve, reject) => { - var ref = this.cachedGroups.get(params.groupId); - if (typeof ref === 'undefined') { - groupRequest.getGroup(params).catch(reject).then(resolve); - } else { - resolve({ - cache: true, - json: ref, - params, - ref - }); - } - }); - }; - - API.applyGroup = function (json) { - var ref = this.cachedGroups.get(json.id); - json.rules = $utils.replaceBioSymbols(json.rules); - json.name = $utils.replaceBioSymbols(json.name); - json.description = $utils.replaceBioSymbols(json.description); - if (typeof ref === 'undefined') { - ref = { - id: '', - name: '', - shortCode: '', - description: '', - bannerId: '', - bannerUrl: '', - createdAt: '', - discriminator: '', - galleries: [], - iconId: '', - iconUrl: '', - isVerified: false, - joinState: '', - languages: [], - links: [], - memberCount: 0, - memberCountSyncedAt: '', - membershipStatus: '', - onlineMemberCount: 0, - ownerId: '', - privacy: '', - rules: null, - tags: [], - // in group - initialRoleIds: [], - myMember: { - bannedAt: null, - groupId: '', - has2FA: false, - id: '', - isRepresenting: false, - isSubscribedToAnnouncements: false, - joinedAt: '', - managerNotes: '', - membershipStatus: '', - permissions: [], - roleIds: [], - userId: '', - visibility: '', - _created_at: '', - _id: '', - _updated_at: '' - }, - updatedAt: '', - // includeRoles: true - roles: [], - // group list - $memberId: '', - groupId: '', - isRepresenting: false, - memberVisibility: false, - mutualGroup: false, - // VRCX - $languages: [], - ...json - }; - this.cachedGroups.set(ref.id, ref); - } else { - if (this.currentUserGroups.has(ref.id)) { - // compare group props - if ( - ref.ownerId && - json.ownerId && - ref.ownerId !== json.ownerId - ) { - // owner changed - $app.groupOwnerChange(json, ref.ownerId, json.ownerId); - } - if (ref.name && json.name && ref.name !== json.name) { - // name changed - $app.groupChange( - json, - `Name changed from ${ref.name} to ${json.name}` - ); - } - if (ref.myMember?.roleIds && json.myMember?.roleIds) { - var oldRoleIds = ref.myMember.roleIds; - var newRoleIds = json.myMember.roleIds; - if ( - oldRoleIds.length !== newRoleIds.length || - !oldRoleIds.every( - (value, index) => value === newRoleIds[index] - ) - ) { - // roleIds changed - $app.groupRoleChange( - json, - ref.roles, - json.roles, - oldRoleIds, - newRoleIds - ); - } - } - } - if (json.myMember) { - if (typeof json.myMember.roleIds === 'undefined') { - // keep roleIds - json.myMember.roleIds = ref.myMember.roleIds; - } - if (typeof json.myMember.isRepresenting !== 'undefined') { - json.myMember.isRepresenting = - ref.myMember.isRepresenting; - } - Object.assign(ref.myMember, json.myMember); - } - Object.assign(ref, json); - } - // update myMember without fetching member - if (typeof json.memberVisibility !== 'undefined') { - ref.myMember.visibility = json.memberVisibility; - } - if (typeof json.isRepresenting !== 'undefined') { - ref.myMember.isRepresenting = json.isRepresenting; - } - if (typeof json.membershipStatus !== 'undefined') { - ref.myMember.membershipStatus = json.membershipStatus; - } - if (typeof json.roleIds !== 'undefined') { - ref.myMember.roleIds = json.roleIds; - } - ref.$url = `https://vrc.group/${ref.shortCode}.${ref.discriminator}`; - this.applyGroupLanguage(ref); - - var currentUserGroupRef = this.currentUserGroups.get(ref.id); - if (currentUserGroupRef && currentUserGroupRef !== ref) { - this.currentUserGroups.set(ref.id, ref); - } - - return ref; - }; - - API.applyGroupMember = function (json) { - if (typeof json?.user !== 'undefined') { - if (json.userId === this.currentUser.id) { - json.user = this.currentUser; - json.$displayName = this.currentUser.displayName; - } else { - var ref = this.cachedUsers.get(json.user.id); - if (typeof ref !== 'undefined') { - json.user = ref; - json.$displayName = ref.displayName; - } else { - json.$displayName = json.user?.displayName; - } - } - } - // update myMember without fetching member - if (json?.userId === this.currentUser.id) { - var ref = this.cachedGroups.get(json.groupId); - if (typeof ref !== 'undefined') { - this.$emit('GROUP', { - json: { - ...ref, - memberVisibility: json.visibility, - isRepresenting: json.isRepresenting, - isSubscribedToAnnouncements: - json.isSubscribedToAnnouncements, - joinedAt: json.joinedAt, - roleIds: json.roleIds, - membershipStatus: json.membershipStatus - }, - params: { - groupId: json.groupId - } - }); - } - } - - return json; - }; - - API.applyGroupLanguage = function (ref) { - ref.$languages = []; - var { languages } = ref; - if (!languages) { - return; - } - for (var language of languages) { - var value = $app.subsetOfLanguages[language]; - if (typeof value === 'undefined') { - continue; - } - ref.$languages.push({ - key: language, - value - }); - } - }; - } - - _data = { - currentUserGroupsInit: false, - // maybe unnecessary - // groupDialogLastMembers: '', - // groupDialogLastGallery: '', - groupMembersSearchTimer: null, - groupMembersSearchPending: false, - isGroupGalleryLoading: false, - - groupDialog: { - visible: false, - loading: false, - isGetGroupDialogGroupLoading: false, - treeData: [], - id: '', - inGroup: false, - ownerDisplayName: '', - ref: {}, - announcement: {}, - posts: [], - postsFiltered: [], - members: [], - memberSearch: '', - memberSearchResults: [], - instances: [], - memberRoles: [], - memberFilter: { - name: $t('dialog.group.members.filters.everyone'), - id: null - }, - memberSortOrder: { - name: $t('dialog.group.members.sorting.joined_at_desc'), - value: 'joinedAt:desc' - }, - postsSearch: '', - galleries: {} - }, - inviteGroupDialog: { - visible: false, - loading: false, - groupId: '', - groupName: '', - userId: '', - userIds: [], - userObject: {} - } - }; - - _methods = { - blockGroup(groupId) { - this.$confirm( - 'Are you sure you want to block this group?', - 'Confirm', - { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - callback: (action) => { - if (action === 'confirm') { - groupRequest - .blockGroup({ - groupId - }) - .then((args) => { - // API.$on('GROUP:BLOCK', function (args) { - if ( - this.groupDialog.visible && - this.groupDialog.id === - args.params.groupId - ) { - this.showGroupDialog( - args.params.groupId - ); - } - // }); - }); - } - } - } - ); - }, - - unblockGroup(groupId) { - this.$confirm( - 'Are you sure you want to unblock this group?', - 'Confirm', - { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - callback: (action) => { - if (action === 'confirm') { - groupRequest - .unblockGroup({ - groupId, - userId: API.currentUser.id - }) - .then((args) => { - // API.$on('GROUP:UNBLOCK', function (args) { - if ( - this.groupDialog.visible && - this.groupDialog.id === - args.params.groupId - ) { - this.showGroupDialog( - args.params.groupId - ); - } - // }); - }); - } - } - } - ); - }, - - async groupOwnerChange(ref, oldUserId, newUserId) { - var oldUser = await userRequest.getCachedUser({ - userId: oldUserId - }); - var newUser = await userRequest.getCachedUser({ - userId: newUserId - }); - var oldDisplayName = oldUser?.ref?.displayName; - var newDisplayName = newUser?.ref?.displayName; - - this.groupChange( - ref, - `Owner changed from ${oldDisplayName} to ${newDisplayName}` - ); - }, - - groupRoleChange(ref, oldRoles, newRoles, oldRoleIds, newRoleIds) { - // check for removed/added roleIds - for (var roleId of oldRoleIds) { - if (!newRoleIds.includes(roleId)) { - var roleName = ''; - var role = oldRoles.find( - (fineRole) => fineRole.id === roleId - ); - if (role) { - roleName = role.name; - } - this.groupChange(ref, `Role ${roleName} removed`); - } - } - for (var roleId of newRoleIds) { - if (!oldRoleIds.includes(roleId)) { - var roleName = ''; - var role = newRoles.find( - (fineRole) => fineRole.id === roleId - ); - if (role) { - roleName = role.name; - } - this.groupChange(ref, `Role ${roleName} added`); - } - } - }, - - groupChange(ref, message) { - if (!this.currentUserGroupsInit) { - return; - } - // oh the level of cursed for compibility - var json = { - id: Math.random().toString(36), - type: 'groupChange', - senderUserId: ref.id, - senderUsername: ref.name, - imageUrl: ref.iconUrl, - details: { - imageUrl: ref.iconUrl - }, - message, - created_at: new Date().toJSON() - }; - API.$emit('NOTIFICATION', { - json, - params: { - notificationId: json.id - } - }); - - // delay to wait for json to be assigned to ref - workerTimers.setTimeout(this.saveCurrentUserGroups, 100); - }, - - saveCurrentUserGroups() { - if (!this.currentUserGroupsInit) { - return; - } - var groups = []; - for (var ref of API.currentUserGroups.values()) { - groups.push({ - id: ref.id, - name: ref.name, - ownerId: ref.ownerId, - iconUrl: ref.iconUrl, - roles: ref.roles, - roleIds: ref.myMember?.roleIds - }); - } - configRepository.setString( - `VRCX_currentUserGroups_${API.currentUser.id}`, - JSON.stringify(groups) - ); - }, - - async loadCurrentUserGroups(userId, groups) { - var savedGroups = JSON.parse( - await configRepository.getString( - `VRCX_currentUserGroups_${userId}`, - '[]' - ) - ); - API.cachedGroups.clear(); - API.currentUserGroups.clear(); - for (var group of savedGroups) { - var json = { - id: group.id, - name: group.name, - iconUrl: group.iconUrl, - ownerId: group.ownerId, - roles: group.roles, - myMember: { - roleIds: group.roleIds - } - }; - var ref = API.applyGroup(json); - API.currentUserGroups.set(group.id, ref); - } - - if (groups) { - const promises = groups.map(async (groupId) => { - const groupRef = API.cachedGroups.get(groupId); - - if ( - typeof groupRef !== 'undefined' && - groupRef.roles?.length > 0 - ) { - return; - } - - try { - console.log( - `Fetching group with missing roles ${groupId}` - ); - const args = await groupRequest.getGroup({ - groupId, - includeRoles: true - }); - const ref = API.applyGroup(args.json); - API.currentUserGroups.set(groupId, ref); - } catch (err) { - console.error(err); - } - }); - - await Promise.allSettled(promises); - } - - this.currentUserGroupsInit = true; - this.getCurrentUserGroups(); - }, - - async getCurrentUserGroups() { - var args = await groupRequest.getGroups({ - userId: API.currentUser.id - }); - API.currentUserGroups.clear(); - for (var group of args.json) { - var ref = API.applyGroup(group); - if (!API.currentUserGroups.has(group.id)) { - API.currentUserGroups.set(group.id, ref); - } - } - await groupRequest.getGroupPermissions({ - userId: API.currentUser.id - }); - this.saveCurrentUserGroups(); - }, - - showGroupDialog(groupId) { - if (!groupId) { - return; - } - var D = this.groupDialog; - D.visible = true; - D.loading = true; - D.id = groupId; - D.inGroup = false; - D.ownerDisplayName = ''; - D.treeData = []; - D.announcement = {}; - D.posts = []; - D.postsFiltered = []; - D.instances = []; - D.memberRoles = []; - D.memberSearch = ''; - D.memberSearchResults = []; - D.galleries = {}; - D.members = []; - D.memberFilter = this.groupDialogFilterOptions.everyone; - API.getCachedGroup({ - groupId - }) - .catch((err) => { - D.loading = false; - D.visible = false; - this.$message({ - message: 'Failed to load group', - type: 'error' - }); - throw err; - }) - .then((args) => { - if (groupId === args.ref.id) { - D.loading = false; - D.ref = args.ref; - D.inGroup = args.ref.membershipStatus === 'member'; - D.ownerDisplayName = args.ref.ownerId; - userRequest - .getCachedUser({ - userId: args.ref.ownerId - }) - .then((args1) => { - D.ownerDisplayName = args1.ref.displayName; - return args1; - }); - this.applyGroupDialogInstances(); - this.getGroupDialogGroup(groupId); - } - }); - }, - - getGroupDialogGroup(groupId) { - var D = this.groupDialog; - D.isGetGroupDialogGroupLoading = false; - return groupRequest - .getGroup({ groupId, includeRoles: true }) - .catch((err) => { - throw err; - }) - .then((args1) => { - if (D.id === args1.ref.id) { - D.ref = args1.ref; - D.inGroup = args1.ref.membershipStatus === 'member'; - for (var role of args1.ref.roles) { - if ( - D.ref && - D.ref.myMember && - Array.isArray(D.ref.myMember.roleIds) && - D.ref.myMember.roleIds.includes(role.id) - ) { - D.memberRoles.push(role); - } - } - API.getAllGroupPosts({ - groupId - }); - D.isGetGroupDialogGroupLoading = true; - if (D.inGroup) { - groupRequest - .getGroupInstances({ - groupId - }) - .then((args) => { - // API.$on('GROUP:INSTANCES', function (args) { - if ( - this.groupDialog.id === - args.params.groupId - ) { - this.applyGroupDialogInstances( - args.json.instances - ); - } - // }); - - // API.$on('GROUP:INSTANCES', function (args) { - for (const json of args.json.instances) { - this.$emit('INSTANCE', { - json, - params: { - fetchedAt: args.json.fetchedAt - } - }); - worldRequest - .getCachedWorld({ - worldId: json.world.id - }) - .then((args1) => { - json.world = args1.ref; - return args1; - }); - // get queue size etc - instanceRequest.getInstance({ - worldId: json.worldId, - instanceId: json.instanceId - }); - } - // }); - }); - } - } - this.$nextTick( - () => (D.isGetGroupDialogGroupLoading = false) - ); - return args1; - }); - }, - - groupDialogCommand(command) { - var D = this.groupDialog; - if (D.visible === false) { - return; - } - switch (command) { - case 'Refresh': - this.showGroupDialog(D.id); - break; - case 'Leave Group': - this.leaveGroupPrompt(D.id); - break; - case 'Block Group': - this.blockGroup(D.id); - break; - case 'Unblock Group': - this.unblockGroup(D.id); - break; - case 'Visibility Everyone': - this.setGroupVisibility(D.id, 'visible'); - break; - case 'Visibility Friends': - this.setGroupVisibility(D.id, 'friends'); - break; - case 'Visibility Hidden': - this.setGroupVisibility(D.id, 'hidden'); - break; - case 'Subscribe To Announcements': - this.setGroupSubscription(D.id, true); - break; - case 'Unsubscribe To Announcements': - this.setGroupSubscription(D.id, false); - break; - } - }, - - leaveGroup(groupId) { - groupRequest - .leaveGroup({ - groupId - }) - .then((args) => { - const groupId = args.params.groupId; - if ( - this.groupDialog.visible && - this.groupDialog.id === groupId - ) { - this.groupDialog.inGroup = false; - this.getGroupDialogGroup(groupId); - } - if ( - this.userDialog.visible && - this.userDialog.id === API.currentUser.id && - this.userDialog.representedGroup.id === groupId - ) { - this.getCurrentUserRepresentedGroup(); - } - }); - }, - - leaveGroupPrompt(groupId) { - this.$confirm( - 'Are you sure you want to leave this group?', - 'Confirm', - { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - callback: (action) => { - if (action === 'confirm') { - this.leaveGroup(groupId); - } - } - } - ); - }, - - setGroupVisibility(groupId, visibility) { - return groupRequest - .setGroupMemberProps(API.currentUser.id, groupId, { - visibility - }) - .then((args) => { - this.$message({ - message: 'Group visibility updated', - type: 'success' - }); - return args; - }); - }, - - setGroupSubscription(groupId, subscribe) { - return groupRequest - .setGroupMemberProps(API.currentUser.id, groupId, { - isSubscribedToAnnouncements: subscribe - }) - .then((args) => { - this.$message({ - message: 'Group subscription updated', - type: 'success' - }); - return args; - }); - }, - - onGroupJoined(groupId) { - // NOTE: don't know why need this - // if ( - // this.groupMemberModeration.visible && - // this.groupMemberModeration.id === groupId - // ) { - // // ignore this event if we were the one to trigger it - // return; - // } - if (!API.currentUserGroups.has(groupId)) { - API.currentUserGroups.set(groupId, { - id: groupId, - name: '', - iconUrl: '' - }); - groupRequest - .getGroup({ groupId, includeRoles: true }) - .then((args) => { - API.applyGroup(args.json); // make sure this runs before saveCurrentUserGroups - this.saveCurrentUserGroups(); - return args; - }); - } - }, - - onGroupLeft(groupId) { - if (this.groupDialog.visible && this.groupDialog.id === groupId) { - this.showGroupDialog(groupId); - } - if (API.currentUserGroups.has(groupId)) { - API.currentUserGroups.delete(groupId); - API.getCachedGroup({ groupId }).then((args) => { - this.groupChange(args.ref, 'Left group'); - }); - } - }, - - updateGroupPostSearch() { - var D = this.groupDialog; - var search = D.postsSearch.toLowerCase(); - D.postsFiltered = D.posts.filter((post) => { - if (search === '') { - return true; - } - if (post.title.toLowerCase().includes(search)) { - return true; - } - if (post.text.toLowerCase().includes(search)) { - return true; - } - return false; - }); - }, - - getCurrentUserRepresentedGroup() { - return groupRequest - .getRepresentedGroup({ - userId: API.currentUser.id - }) - .then((args) => { - this.userDialog.representedGroup = args.json; - return args; - }); - } - }; -} diff --git a/src/classes/inventory.js b/src/classes/inventory.js deleted file mode 100644 index d6228ba8..00000000 --- a/src/classes/inventory.js +++ /dev/null @@ -1,55 +0,0 @@ -import * as workerTimers from 'worker-timers'; -import configRepository from '../service/config.js'; -import database from '../service/database.js'; -import { baseClass, $app, API, $t, $utils } from './baseClass.js'; -import { inventoryRequest } from '../api'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - init() { - API.currentUserInventory = new Map(); - API.$on('LOGIN', function () { - API.currentUserInventory.clear(); - }); - } - - _data = { - inventoryTable: [] - }; - - _methods = { - async getInventory() { - this.inventoryTable = []; - API.currentUserInventory.clear(); - var params = { - n: 100, - offset: 0, - order: 'newest' - }; - this.galleryDialogInventoryLoading = true; - try { - for (let i = 0; i < 100; i++) { - params.offset = i * params.n; - const args = - await inventoryRequest.getInventoryItems(params); - for (const item of args.json.data) { - API.currentUserInventory.set(item.id, item); - if (!item.flags.includes('ugc')) { - this.inventoryTable.push(item); - } - } - if (args.json.data.length === 0) { - break; - } - } - } catch (error) { - console.error('Error fetching inventory items:', error); - } finally { - this.galleryDialogInventoryLoading = false; - } - } - }; -} diff --git a/src/classes/languages.js b/src/classes/languages.js deleted file mode 100644 index a9f1cae5..00000000 --- a/src/classes/languages.js +++ /dev/null @@ -1,41 +0,0 @@ -import { baseClass, $app, API, $t, $utils } from './baseClass.js'; -import { userRequest } from '../api'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - init() { - API.$on('CONFIG', function (args) { - var languages = - args.ref?.constants?.LANGUAGE?.SPOKEN_LANGUAGE_OPTIONS; - if (!languages) { - return; - } - $app.subsetOfLanguages = languages; - var data = []; - for (var key in languages) { - var value = languages[key]; - data.push({ - key, - value - }); - } - $app.languageDialog.languages = data; - }); - } - - _data = { - subsetOfLanguages: [], - - languageDialog: { - visible: false, - loading: false, - languageChoice: false, - languages: [] - } - }; - - _methods = {}; -} diff --git a/src/classes/memos.js b/src/classes/memos.js deleted file mode 100644 index 30856fbd..00000000 --- a/src/classes/memos.js +++ /dev/null @@ -1,106 +0,0 @@ -import { baseClass, $app, API, $t, $utils } from './baseClass.js'; -import database from '../service/database.js'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - init() {} - - _data = { - hideUserMemos: false - }; - - _methods = { - async migrateMemos() { - var json = JSON.parse(await VRCXStorage.GetAll()); - for (var line in json) { - if (line.substring(0, 8) === 'memo_usr') { - var userId = line.substring(5); - var memo = json[line]; - if (memo) { - await this.saveUserMemo(userId, memo); - VRCXStorage.Remove(`memo_${userId}`); - } - } - } - }, - - async getUserMemo(userId) { - try { - return await database.getUserMemo(userId); - } catch (err) { - console.error(err); - return { - userId: '', - editedAt: '', - memo: '' - }; - } - }, - - async saveUserMemo(id, memo) { - if (memo) { - await database.setUserMemo({ - userId: id, - editedAt: new Date().toJSON(), - memo - }); - } else { - await database.deleteUserMemo(id); - } - var ref = this.friends.get(id); - if (ref) { - ref.memo = String(memo || ''); - if (memo) { - var array = memo.split('\n'); - ref.$nickName = array[0]; - } else { - ref.$nickName = ''; - } - } - }, - - async getAllUserMemos() { - var memos = await database.getAllUserMemos(); - memos.forEach((memo) => { - var ref = $app.friends.get(memo.userId); - if (typeof ref !== 'undefined') { - ref.memo = memo.memo; - ref.$nickName = ''; - if (memo.memo) { - var array = memo.memo.split('\n'); - ref.$nickName = array[0]; - } - } - }); - }, - - async getWorldMemo(worldId) { - try { - return await database.getWorldMemo(worldId); - } catch (err) { - console.error(err); - return { - worldId: '', - editedAt: '', - memo: '' - }; - } - }, - - async getAvatarMemo(avatarId) { - try { - return await database.getAvatarMemoDB(avatarId); - } catch (err) { - console.error(err); - return { - avatarId: '', - editedAt: '', - memo: '' - }; - } - } - }; -} diff --git a/src/classes/prompts.js b/src/classes/prompts.js deleted file mode 100644 index 799bd8b4..00000000 --- a/src/classes/prompts.js +++ /dev/null @@ -1,574 +0,0 @@ -import * as workerTimers from 'worker-timers'; -import configRepository from '../service/config.js'; -import database from '../service/database.js'; -import { baseClass, $app, API, $t, $utils } from './baseClass.js'; -import { avatarRequest, favoriteRequest, worldRequest } from '../api'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - _methods = { - promptTOTP() { - if (this.twoFactorAuthDialogVisible) { - return; - } - AppApi.FlashWindow(); - this.twoFactorAuthDialogVisible = true; - this.$prompt( - $t('prompt.totp.description'), - $t('prompt.totp.header'), - { - distinguishCancelAndClose: true, - cancelButtonText: $t('prompt.totp.use_otp'), - confirmButtonText: $t('prompt.totp.verify'), - inputPlaceholder: $t('prompt.totp.input_placeholder'), - inputPattern: /^[0-9]{6}$/, - inputErrorMessage: $t('prompt.totp.input_error'), - callback: (action, instance) => { - if (action === 'confirm') { - API.verifyTOTP({ - code: instance.inputValue.trim() - }) - .catch((err) => { - $app.clearCookiesTryLogin(); - throw err; - }) - .then((args) => { - API.getCurrentUser(); - return args; - }); - } else if (action === 'cancel') { - this.promptOTP(); - } - }, - beforeClose: (action, instance, done) => { - this.twoFactorAuthDialogVisible = false; - done(); - } - } - ); - }, - - promptOTP() { - if (this.twoFactorAuthDialogVisible) { - return; - } - this.twoFactorAuthDialogVisible = true; - this.$prompt( - $t('prompt.otp.description'), - $t('prompt.otp.header'), - { - distinguishCancelAndClose: true, - cancelButtonText: $t('prompt.otp.use_totp'), - confirmButtonText: $t('prompt.otp.verify'), - inputPlaceholder: $t('prompt.otp.input_placeholder'), - inputPattern: /^[a-z0-9]{4}-[a-z0-9]{4}$/, - inputErrorMessage: $t('prompt.otp.input_error'), - callback: (action, instance) => { - if (action === 'confirm') { - API.verifyOTP({ - code: instance.inputValue.trim() - }) - .catch((err) => { - $app.clearCookiesTryLogin(); - throw err; - }) - .then((args) => { - API.getCurrentUser(); - return args; - }); - } else if (action === 'cancel') { - this.promptTOTP(); - } - }, - beforeClose: (action, instance, done) => { - this.twoFactorAuthDialogVisible = false; - done(); - } - } - ); - }, - - promptEmailOTP() { - if (this.twoFactorAuthDialogVisible) { - return; - } - AppApi.FlashWindow(); - this.twoFactorAuthDialogVisible = true; - this.$prompt( - $t('prompt.email_otp.description'), - $t('prompt.email_otp.header'), - { - distinguishCancelAndClose: true, - cancelButtonText: $t('prompt.email_otp.resend'), - confirmButtonText: $t('prompt.email_otp.verify'), - inputPlaceholder: $t('prompt.email_otp.input_placeholder'), - inputPattern: /^[0-9]{6}$/, - inputErrorMessage: $t('prompt.email_otp.input_error'), - callback: (action, instance) => { - if (action === 'confirm') { - API.verifyEmailOTP({ - code: instance.inputValue.trim() - }) - .catch((err) => { - this.promptEmailOTP(); - throw err; - }) - .then((args) => { - API.getCurrentUser(); - return args; - }); - } else if (action === 'cancel') { - this.resendEmail2fa(); - } - }, - beforeClose: (action, instance, done) => { - this.twoFactorAuthDialogVisible = false; - done(); - } - } - ); - }, - - promptOmniDirectDialog() { - this.$prompt( - $t('prompt.direct_access_omni.description'), - $t('prompt.direct_access_omni.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.direct_access_omni.ok'), - cancelButtonText: $t('prompt.direct_access_omni.cancel'), - inputPattern: /\S+/, - inputErrorMessage: $t( - 'prompt.direct_access_omni.input_error' - ), - callback: (action, instance) => { - if (action === 'confirm' && instance.inputValue) { - var input = instance.inputValue.trim(); - if (!this.directAccessParse(input)) { - this.$message({ - message: $t( - 'prompt.direct_access_omni.message.error' - ), - type: 'error' - }); - } - } - } - } - ); - }, - - promptNotificationTimeout() { - this.$prompt( - $t('prompt.notification_timeout.description'), - $t('prompt.notification_timeout.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.notification_timeout.ok'), - cancelButtonText: $t('prompt.notification_timeout.cancel'), - inputValue: this.notificationTimeout / 1000, - inputPattern: /\d+$/, - inputErrorMessage: $t( - 'prompt.notification_timeout.input_error' - ), - callback: async (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue && - !isNaN(instance.inputValue) - ) { - this.notificationTimeout = Math.trunc( - Number(instance.inputValue) * 1000 - ); - await configRepository.setString( - 'VRCX_notificationTimeout', - this.notificationTimeout - ); - this.updateVRConfigVars(); - } - } - } - ); - }, - - promptPhotonOverlayMessageTimeout() { - this.$prompt( - $t('prompt.overlay_message_timeout.description'), - $t('prompt.overlay_message_timeout.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.overlay_message_timeout.ok'), - cancelButtonText: $t( - 'prompt.overlay_message_timeout.cancel' - ), - inputValue: this.photonOverlayMessageTimeout / 1000, - inputPattern: /\d+$/, - inputErrorMessage: $t( - 'prompt.overlay_message_timeout.input_error' - ), - callback: async (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue && - !isNaN(instance.inputValue) - ) { - this.photonOverlayMessageTimeout = Math.trunc( - Number(instance.inputValue) * 1000 - ); - await configRepository.setString( - 'VRCX_photonOverlayMessageTimeout', - this.photonOverlayMessageTimeout - ); - this.updateVRConfigVars(); - } - } - } - ); - }, - - promptRenameWorld(world) { - this.$prompt( - $t('prompt.rename_world.description'), - $t('prompt.rename_world.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.rename_world.ok'), - cancelButtonText: $t('prompt.rename_world.cancel'), - inputValue: world.ref.name, - inputErrorMessage: $t('prompt.rename_world.input_error'), - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue !== world.ref.name - ) { - worldRequest - .saveWorld({ - id: world.id, - name: instance.inputValue - }) - .then((args) => { - this.$message({ - message: $t( - 'prompt.rename_world.message.success' - ), - type: 'success' - }); - return args; - }); - } - } - } - ); - }, - - promptChangeWorldDescription(world) { - this.$prompt( - $t('prompt.change_world_description.description'), - $t('prompt.change_world_description.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.change_world_description.ok'), - cancelButtonText: $t( - 'prompt.change_world_description.cancel' - ), - inputValue: world.ref.description, - inputErrorMessage: $t( - 'prompt.change_world_description.input_error' - ), - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue !== world.ref.description - ) { - worldRequest - .saveWorld({ - id: world.id, - description: instance.inputValue - }) - .then((args) => { - this.$message({ - message: $t( - 'prompt.change_world_description.message.success' - ), - type: 'success' - }); - return args; - }); - } - } - } - ); - }, - - promptChangeWorldCapacity(world) { - this.$prompt( - $t('prompt.change_world_capacity.description'), - $t('prompt.change_world_capacity.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.change_world_capacity.ok'), - cancelButtonText: $t('prompt.change_world_capacity.cancel'), - inputValue: world.ref.capacity, - inputPattern: /\d+$/, - inputErrorMessage: $t( - 'prompt.change_world_capacity.input_error' - ), - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue !== world.ref.capacity - ) { - worldRequest - .saveWorld({ - id: world.id, - capacity: instance.inputValue - }) - .then((args) => { - this.$message({ - message: $t( - 'prompt.change_world_capacity.message.success' - ), - type: 'success' - }); - return args; - }); - } - } - } - ); - }, - - promptChangeWorldRecommendedCapacity(world) { - this.$prompt( - $t('prompt.change_world_recommended_capacity.description'), - $t('prompt.change_world_recommended_capacity.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.change_world_capacity.ok'), - cancelButtonText: $t('prompt.change_world_capacity.cancel'), - inputValue: world.ref.recommendedCapacity, - inputPattern: /\d+$/, - inputErrorMessage: $t( - 'prompt.change_world_recommended_capacity.input_error' - ), - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue !== - world.ref.recommendedCapacity - ) { - worldRequest - .saveWorld({ - id: world.id, - recommendedCapacity: instance.inputValue - }) - .then((args) => { - this.$message({ - message: $t( - 'prompt.change_world_recommended_capacity.message.success' - ), - type: 'success' - }); - return args; - }); - } - } - } - ); - }, - - promptChangeWorldYouTubePreview(world) { - this.$prompt( - $t('prompt.change_world_preview.description'), - $t('prompt.change_world_preview.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.change_world_preview.ok'), - cancelButtonText: $t('prompt.change_world_preview.cancel'), - inputValue: world.ref.previewYoutubeId, - inputErrorMessage: $t( - 'prompt.change_world_preview.input_error' - ), - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue !== world.ref.previewYoutubeId - ) { - if (instance.inputValue.length > 11) { - try { - var url = new URL(instance.inputValue); - var id1 = url.pathname; - var id2 = url.searchParams.get('v'); - if (id1 && id1.length === 12) { - instance.inputValue = id1.substring( - 1, - 12 - ); - } - if (id2 && id2.length === 11) { - instance.inputValue = id2; - } - } catch { - this.$message({ - message: $t( - 'prompt.change_world_preview.message.error' - ), - type: 'error' - }); - return; - } - } - if ( - instance.inputValue !== - world.ref.previewYoutubeId - ) { - worldRequest - .saveWorld({ - id: world.id, - previewYoutubeId: instance.inputValue - }) - .then((args) => { - this.$message({ - message: $t( - 'prompt.change_world_preview.message.success' - ), - type: 'success' - }); - return args; - }); - } - } - } - } - ); - }, - - promptMaxTableSizeDialog() { - this.$prompt( - $t('prompt.change_table_size.description'), - $t('prompt.change_table_size.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.change_table_size.save'), - cancelButtonText: $t('prompt.change_table_size.cancel'), - inputValue: this.maxTableSize, - inputPattern: /\d+$/, - inputErrorMessage: $t( - 'prompt.change_table_size.input_error' - ), - callback: async (action, instance) => { - if (action === 'confirm' && instance.inputValue) { - if (instance.inputValue > 10000) { - instance.inputValue = 10000; - } - this.maxTableSize = instance.inputValue; - await configRepository.setString( - 'VRCX_maxTableSize', - this.maxTableSize - ); - database.setmaxTableSize(this.maxTableSize); - this.feedTableLookup(); - this.gameLogTableLookup(); - } - } - } - ); - }, - - promptProxySettings() { - this.$prompt( - $t('prompt.proxy_settings.description'), - $t('prompt.proxy_settings.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.proxy_settings.restart'), - cancelButtonText: $t('prompt.proxy_settings.close'), - inputValue: this.proxyServer, - inputPlaceholder: $t('prompt.proxy_settings.placeholder'), - callback: async (action, instance) => { - this.proxyServer = instance.inputValue; - await VRCXStorage.Set( - 'VRCX_ProxyServer', - this.proxyServer - ); - await VRCXStorage.Flush(); - await new Promise((resolve) => { - workerTimers.setTimeout(resolve, 100); - }); - if (action === 'confirm') { - var isUpgrade = false; - this.restartVRCX(isUpgrade); - } - } - } - ); - }, - - promptPhotonLobbyTimeoutThreshold() { - this.$prompt( - $t('prompt.photon_lobby_timeout.description'), - $t('prompt.photon_lobby_timeout.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.photon_lobby_timeout.ok'), - cancelButtonText: $t('prompt.photon_lobby_timeout.cancel'), - inputValue: this.photonLobbyTimeoutThreshold / 1000, - inputPattern: /\d+$/, - inputErrorMessage: $t( - 'prompt.photon_lobby_timeout.input_error' - ), - callback: async (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue && - !isNaN(instance.inputValue) - ) { - this.photonLobbyTimeoutThreshold = Math.trunc( - Number(instance.inputValue) * 1000 - ); - await configRepository.setString( - 'VRCX_photonLobbyTimeoutThreshold', - this.photonLobbyTimeoutThreshold - ); - } - } - } - ); - }, - - promptAutoClearVRCXCacheFrequency() { - this.$prompt( - $t('prompt.auto_clear_cache.description'), - $t('prompt.auto_clear_cache.header'), - { - distinguishCancelAndClose: true, - confirmButtonText: $t('prompt.auto_clear_cache.ok'), - cancelButtonText: $t('prompt.auto_clear_cache.cancel'), - inputValue: this.clearVRCXCacheFrequency / 3600 / 2, - inputPattern: /\d+$/, - inputErrorMessage: $t( - 'prompt.auto_clear_cache.input_error' - ), - callback: async (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue && - !isNaN(instance.inputValue) - ) { - this.clearVRCXCacheFrequency = Math.trunc( - Number(instance.inputValue) * 3600 * 2 - ); - await configRepository.setString( - 'VRCX_clearVRCXCacheFrequency', - this.clearVRCXCacheFrequency - ); - } - } - } - ); - } - }; -} diff --git a/src/classes/restoreFriendOrder.js b/src/classes/restoreFriendOrder.js deleted file mode 100644 index 6c25960b..00000000 --- a/src/classes/restoreFriendOrder.js +++ /dev/null @@ -1,284 +0,0 @@ -import * as workerTimers from 'worker-timers'; -import configRepository from '../service/config.js'; -import database from '../service/database.js'; -import { baseClass, $app, API, $t, $utils } from './baseClass.js'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - init() {} - - _data = {}; - - _methods = { - async tryRestoreFriendNumber() { - var lastUpdate = await configRepository.getString( - `VRCX_lastStoreTime_${API.currentUser.id}` - ); - if (lastUpdate == -4) { - // this means the backup was already applied - return; - } - var status = false; - this.friendNumber = 0; - for (var ref of this.friendLog.values()) { - ref.friendNumber = 0; - } - try { - if (lastUpdate) { - // backup ready to try apply - status = await this.restoreFriendNumber(); - } - // needs to be in reverse because we don't know the starting number - this.applyFriendLogFriendOrderInReverse(); - } catch (err) { - console.error(err); - } - // if (status) { - // this.$message({ - // message: 'Friend order restored from backup', - // type: 'success', - // duration: 0, - // showClose: true - // }); - // } else if (this.friendLogTable.data.length > 0) { - // this.$message({ - // message: - // 'No backup found, friend order partially restored from friendLog', - // type: 'success', - // duration: 0, - // showClose: true - // }); - // } - await configRepository.setString( - `VRCX_lastStoreTime_${API.currentUser.id}`, - -4 - ); - }, - - async restoreFriendNumber() { - var storedData = null; - try { - var data = await configRepository.getString( - `VRCX_friendOrder_${API.currentUser.id}` - ); - if (data) { - var storedData = JSON.parse(data); - } - } catch (err) { - console.error(err); - } - if (!storedData || storedData.length === 0) { - var message = 'whomp whomp, no friend order backup found'; - console.error(message); - return false; - } - - var friendLogTable = this.getFriendLogFriendOrder(); - - // for storedData - var machList = []; - for (var i = 0; i < Object.keys(storedData).length; i++) { - var key = Object.keys(storedData)[i]; - var value = storedData[key]; - var item = this.parseFriendOrderBackup( - friendLogTable, - key, - value - ); - machList.push(item); - } - machList.sort((a, b) => b.matches - a.matches); - console.log( - `friendLog: ${friendLogTable.length} friendOrderBackups:`, - machList - ); - - var bestBackup = machList[0]; - if (!bestBackup?.isValid) { - var message = 'whomp whomp, no valid backup found'; - console.error(message); - return false; - } - - this.applyFriendOrderBackup(bestBackup.table); - this.applyFriendLogFriendOrder(); - await configRepository.setInt( - `VRCX_friendNumber_${API.currentUser.id}`, - this.friendNumber - ); - return true; - }, - - getFriendLogFriendOrder() { - var friendLogTable = []; - for (var i = 0; i < this.friendLogTable.data.length; i++) { - var ref = this.friendLogTable.data[i]; - if (ref.type !== 'Friend') { - continue; - } - if ( - friendLogTable.findIndex((x) => x.id === ref.userId) !== -1 - ) { - // console.log( - // 'ignoring duplicate friend', - // ref.displayName, - // ref.created_at - // ); - continue; - } - friendLogTable.push({ - id: ref.userId, - displayName: ref.displayName, - created_at: ref.created_at - }); - } - var compareByCreatedAt = function (a, b) { - var A = a.created_at; - var B = b.created_at; - if (A < B) { - return -1; - } - if (A > B) { - return 1; - } - return 0; - }; - friendLogTable.sort(compareByCreatedAt); - return friendLogTable; - }, - - applyFriendLogFriendOrder() { - var friendLogTable = this.getFriendLogFriendOrder(); - if (this.friendNumber === 0) { - console.log( - 'No backup applied, applying friend log in reverse' - ); - // this means no FriendOrderBackup was applied - // will need to apply in reverse order instead - return; - } - for (var friendLog of friendLogTable) { - var ref = this.friendLog.get(friendLog.id); - if (!ref || ref.friendNumber) { - continue; - } - ref.friendNumber = ++this.friendNumber; - this.friendLog.set(ref.userId, ref); - database.setFriendLogCurrent(ref); - var friendRef = this.friends.get(friendLog.id); - if (friendRef?.ref) { - friendRef.ref.$friendNumber = ref.friendNumber; - } - } - }, - - applyFriendLogFriendOrderInReverse() { - this.friendNumber = this.friends.size + 1; - var friendLogTable = this.getFriendLogFriendOrder(); - for (var i = friendLogTable.length - 1; i > -1; i--) { - var friendLog = friendLogTable[i]; - var ref = this.friendLog.get(friendLog.id); - if (!ref) { - continue; - } - if (ref.friendNumber) { - break; - } - ref.friendNumber = --this.friendNumber; - this.friendLog.set(ref.userId, ref); - database.setFriendLogCurrent(ref); - var friendRef = this.friends.get(friendLog.id); - if (friendRef?.ref) { - friendRef.ref.$friendNumber = ref.friendNumber; - } - } - this.friendNumber = this.friends.size; - console.log('Applied friend order from friendLog'); - }, - - parseFriendOrderBackup(friendLogTable, created_at, backupUserIds) { - var backupTable = []; - for (var i = 0; i < backupUserIds.length; i++) { - var userId = backupUserIds[i]; - var ctx = this.friends.get(userId); - if (ctx) { - backupTable.push({ - id: ctx.id, - displayName: ctx.name - }); - } - } - - // var compareTable = []; - // compare 2 tables, find max amount of id's in same order - var maxMatches = 0; - var currentMatches = 0; - var backupIndex = 0; - for (var i = 0; i < friendLogTable.length; i++) { - var isMatch = false; - var ref = friendLogTable[i]; - if (backupIndex <= 0) { - backupIndex = backupTable.findIndex((x) => x.id === ref.id); - if (backupIndex !== -1) { - currentMatches = 1; - } - } else if (backupTable[backupIndex].id === ref.id) { - currentMatches++; - isMatch = true; - } else { - var backupIndex = backupTable.findIndex( - (x) => x.id === ref.id - ); - if (backupIndex !== -1) { - currentMatches = 1; - } - } - if (backupIndex === backupTable.length - 1) { - backupIndex = 0; - } else { - backupIndex++; - } - if (currentMatches > maxMatches) { - maxMatches = currentMatches; - } - // compareTable.push({ - // id: ref.id, - // displayName: ref.displayName, - // match: isMatch - // }); - } - - var lerp = (a, b, alpha) => { - return a + alpha * (b - a); - }; - return { - matches: parseFloat(`${maxMatches}.${created_at}`), - table: backupUserIds, - isValid: maxMatches > lerp(4, 10, backupTable.length / 1000) // pls no collisions - }; - }, - - applyFriendOrderBackup(userIdOrder) { - for (var i = 0; i < userIdOrder.length; i++) { - var userId = userIdOrder[i]; - var ctx = this.friends.get(userId); - var ref = ctx?.ref; - if (!ref || ref.$friendNumber) { - continue; - } - var friendLogCurrent = { - userId, - displayName: ref.displayName, - trustLevel: ref.$trustLevel, - friendNumber: i + 1 - }; - this.friendLog.set(userId, friendLogCurrent); - database.setFriendLogCurrent(friendLogCurrent); - this.friendNumber = i + 1; - } - } - }; -} diff --git a/src/classes/sharedFeed.js b/src/classes/sharedFeed.js deleted file mode 100644 index 71eedc91..00000000 --- a/src/classes/sharedFeed.js +++ /dev/null @@ -1,577 +0,0 @@ -import * as workerTimers from 'worker-timers'; -import { baseClass, $app, API } from './baseClass.js'; -import { worldRequest, groupRequest } from '../api'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - _data = { - sharedFeed: { - gameLog: { - wrist: [], - lastEntryDate: '' - }, - feedTable: { - wrist: [], - lastEntryDate: '' - }, - notificationTable: { - wrist: [], - lastEntryDate: '' - }, - friendLogTable: { - wrist: [], - lastEntryDate: '' - }, - moderationAgainstTable: { - wrist: [], - lastEntryDate: '' - }, - pendingUpdate: false - }, - updateSharedFeedTimer: null, - updateSharedFeedPending: false, - updateSharedFeedPendingForceUpdate: false - }; - - _methods = { - updateSharedFeed(forceUpdate) { - if (!this.friendLogInitStatus) { - return; - } - if (this.updateSharedFeedTimer) { - if (forceUpdate) { - this.updateSharedFeedPendingForceUpdate = true; - } - this.updateSharedFeedPending = true; - } else { - this.updateSharedExecute(forceUpdate); - this.updateSharedFeedTimer = setTimeout(() => { - if (this.updateSharedFeedPending) { - this.updateSharedExecute( - this.updateSharedFeedPendingForceUpdate - ); - } - this.updateSharedFeedTimer = null; - }, 150); - } - }, - - updateSharedExecute(forceUpdate) { - try { - this.updateSharedFeedDebounce(forceUpdate); - } catch (err) { - console.error(err); - } - this.updateSharedFeedTimer = null; - this.updateSharedFeedPending = false; - this.updateSharedFeedPendingForceUpdate = false; - }, - - updateSharedFeedDebounce(forceUpdate) { - this.updateSharedFeedGameLog(forceUpdate); - this.updateSharedFeedFeedTable(forceUpdate); - this.updateSharedFeedNotificationTable(forceUpdate); - this.updateSharedFeedFriendLogTable(forceUpdate); - this.updateSharedFeedModerationAgainstTable(forceUpdate); - var feeds = this.sharedFeed; - if (!feeds.pendingUpdate) { - return; - } - var wristFeed = []; - wristFeed = wristFeed.concat( - feeds.gameLog.wrist, - feeds.feedTable.wrist, - feeds.notificationTable.wrist, - feeds.friendLogTable.wrist, - feeds.moderationAgainstTable.wrist - ); - // OnPlayerJoining/Traveling - API.currentTravelers.forEach((ref) => { - var isFavorite = this.localFavoriteFriends.has(ref.id); - if ( - (this.sharedFeedFilters.wrist.OnPlayerJoining === - 'Friends' || - (this.sharedFeedFilters.wrist.OnPlayerJoining === - 'VIP' && - isFavorite)) && - !$app.lastLocation.playerList.has(ref.id) - ) { - if (ref.$location.tag === $app.lastLocation.location) { - var feedEntry = { - ...ref, - isFavorite, - isFriend: true, - type: 'OnPlayerJoining' - }; - wristFeed.unshift(feedEntry); - } else { - var worldRef = API.cachedWorlds.get( - ref.$location.worldId - ); - var groupName = ''; - if (ref.$location.groupId) { - var groupRef = API.cachedGroups.get( - ref.$location.groupId - ); - if (typeof groupRef !== 'undefined') { - groupName = groupRef.name; - } else { - // no group cache, fetch group and try again - groupRequest - .getGroup({ - groupId: ref.$location.groupId - }) - .then((args) => { - workerTimers.setTimeout(() => { - // delay to allow for group cache to update - $app.sharedFeed.pendingUpdate = - true; - $app.updateSharedFeed(false); - }, 100); - return args; - }) - .catch((err) => { - console.error(err); - }); - } - } - if (typeof worldRef !== 'undefined') { - var feedEntry = { - created_at: ref.created_at, - type: 'GPS', - userId: ref.id, - displayName: ref.displayName, - location: ref.$location.tag, - worldName: worldRef.name, - groupName, - previousLocation: '', - isFavorite, - time: 0, - isFriend: true, - isTraveling: true - }; - wristFeed.unshift(feedEntry); - } else { - // no world cache, fetch world and try again - worldRequest - .getWorld({ - worldId: ref.$location.worldId - }) - .then((args) => { - workerTimers.setTimeout(() => { - // delay to allow for world cache to update - $app.sharedFeed.pendingUpdate = true; - $app.updateSharedFeed(false); - }, 100); - return args; - }) - .catch((err) => { - console.error(err); - }); - } - } - } - }); - wristFeed.sort(function (a, b) { - if (a.created_at < b.created_at) { - return 1; - } - if (a.created_at > b.created_at) { - return -1; - } - return 0; - }); - wristFeed.splice(16); - AppApi.ExecuteVrFeedFunction( - 'wristFeedUpdate', - JSON.stringify(wristFeed) - ); - this.applyUserDialogLocation(); - this.applyWorldDialogInstances(); - this.applyGroupDialogInstances(); - feeds.pendingUpdate = false; - }, - - updateSharedFeedGameLog(forceUpdate) { - // Location, OnPlayerJoined, OnPlayerLeft - var sessionTable = this.gameLogSessionTable; - var i = sessionTable.length; - if (i > 0) { - if ( - sessionTable[i - 1].created_at === - this.sharedFeed.gameLog.lastEntryDate && - forceUpdate === false - ) { - return; - } - this.sharedFeed.gameLog.lastEntryDate = - sessionTable[i - 1].created_at; - } else { - return; - } - var bias = new Date(Date.now() - 86400000).toJSON(); // 24 hours - var wristArr = []; - var w = 0; - var wristFilter = this.sharedFeedFilters.wrist; - var currentUserLeaveTime = 0; - var locationJoinTime = 0; - for (var i = sessionTable.length - 1; i > -1; i--) { - var ctx = sessionTable[i]; - if (ctx.created_at < bias) { - break; - } - if (ctx.type === 'Notification') { - continue; - } - // on Location change remove OnPlayerLeft - if (ctx.type === 'LocationDestination') { - currentUserLeaveTime = Date.parse(ctx.created_at); - var currentUserLeaveTimeOffset = - currentUserLeaveTime + 5 * 1000; - for (var k = w - 1; k > -1; k--) { - var feedItem = wristArr[k]; - if ( - (feedItem.type === 'OnPlayerLeft' || - feedItem.type === 'BlockedOnPlayerLeft' || - feedItem.type === 'MutedOnPlayerLeft') && - Date.parse(feedItem.created_at) >= - currentUserLeaveTime && - Date.parse(feedItem.created_at) <= - currentUserLeaveTimeOffset - ) { - wristArr.splice(k, 1); - w--; - } - } - } - // on Location change remove OnPlayerJoined - if (ctx.type === 'Location') { - locationJoinTime = Date.parse(ctx.created_at); - var locationJoinTimeOffset = locationJoinTime + 20 * 1000; - for (var k = w - 1; k > -1; k--) { - var feedItem = wristArr[k]; - if ( - (feedItem.type === 'OnPlayerJoined' || - feedItem.type === 'BlockedOnPlayerJoined' || - feedItem.type === 'MutedOnPlayerJoined') && - Date.parse(feedItem.created_at) >= - locationJoinTime && - Date.parse(feedItem.created_at) <= - locationJoinTimeOffset - ) { - wristArr.splice(k, 1); - w--; - } - } - } - // remove current user - if ( - (ctx.type === 'OnPlayerJoined' || - ctx.type === 'OnPlayerLeft' || - ctx.type === 'PortalSpawn') && - ctx.displayName === API.currentUser.displayName - ) { - continue; - } - var isFriend = false; - var isFavorite = false; - if (ctx.userId) { - isFriend = this.friends.has(ctx.userId); - isFavorite = this.localFavoriteFriends.has(ctx.userId); - } else if (ctx.displayName) { - for (var ref of API.cachedUsers.values()) { - if (ref.displayName === ctx.displayName) { - isFriend = this.friends.has(ref.id); - isFavorite = this.localFavoriteFriends.has(ref.id); - break; - } - } - } - // add tag colour - var tagColour = ''; - if (ctx.userId) { - var tagRef = this.customUserTags.get(ctx.userId); - if (typeof tagRef !== 'undefined') { - tagColour = tagRef.colour; - } - } - // BlockedOnPlayerJoined, BlockedOnPlayerLeft, MutedOnPlayerJoined, MutedOnPlayerLeft - if ( - ctx.type === 'OnPlayerJoined' || - ctx.type === 'OnPlayerLeft' - ) { - for (var ref of API.cachedPlayerModerations.values()) { - if ( - ref.targetDisplayName !== ctx.displayName && - ref.sourceUserId !== ctx.userId - ) { - continue; - } - - if (ref.type === 'block') { - var type = `Blocked${ctx.type}`; - } else if (ref.type === 'mute') { - var type = `Muted${ctx.type}`; - } else { - continue; - } - - var entry = { - created_at: ctx.created_at, - type, - displayName: ref.targetDisplayName, - userId: ref.targetUserId, - isFriend, - isFavorite - }; - if ( - wristFilter[type] && - (wristFilter[type] === 'Everyone' || - (wristFilter[type] === 'Friends' && isFriend) || - (wristFilter[type] === 'VIP' && isFavorite)) - ) { - wristArr.unshift(entry); - } - this.queueGameLogNoty(entry); - } - } - // when too many user joins happen at once when switching instances - // the "w" counter maxes out and wont add any more entries - // until the onJoins are cleared by "Location" - // e.g. if a "VideoPlay" occurs between "OnPlayerJoined" and "Location" it wont be added - if ( - w < 50 && - wristFilter[ctx.type] && - (wristFilter[ctx.type] === 'On' || - wristFilter[ctx.type] === 'Everyone' || - (wristFilter[ctx.type] === 'Friends' && isFriend) || - (wristFilter[ctx.type] === 'VIP' && isFavorite)) - ) { - wristArr.push({ - ...ctx, - tagColour, - isFriend, - isFavorite - }); - ++w; - } - } - this.sharedFeed.gameLog.wrist = wristArr; - this.sharedFeed.pendingUpdate = true; - }, - - updateSharedFeedFeedTable(forceUpdate) { - // GPS, Online, Offline, Status, Avatar - var feedSession = this.feedSessionTable; - var i = feedSession.length; - if (i > 0) { - if ( - feedSession[i - 1].created_at === - this.sharedFeed.feedTable.lastEntryDate && - forceUpdate === false - ) { - return; - } - this.sharedFeed.feedTable.lastEntryDate = - feedSession[i - 1].created_at; - } else { - return; - } - var bias = new Date(Date.now() - 86400000).toJSON(); // 24 hours - var wristArr = []; - var w = 0; - var wristFilter = this.sharedFeedFilters.wrist; - for (var i = feedSession.length - 1; i > -1; i--) { - var ctx = feedSession[i]; - if (ctx.created_at < bias) { - break; - } - if (ctx.type === 'Avatar') { - continue; - } - // hide private worlds from feed - if ( - this.hidePrivateFromFeed && - ctx.type === 'GPS' && - ctx.location === 'private' - ) { - continue; - } - var isFriend = this.friends.has(ctx.userId); - var isFavorite = this.localFavoriteFriends.has(ctx.userId); - if ( - w < 20 && - wristFilter[ctx.type] && - (wristFilter[ctx.type] === 'Friends' || - (wristFilter[ctx.type] === 'VIP' && isFavorite)) - ) { - wristArr.push({ - ...ctx, - isFriend, - isFavorite - }); - ++w; - } - } - this.sharedFeed.feedTable.wrist = wristArr; - this.sharedFeed.pendingUpdate = true; - }, - - updateSharedFeedNotificationTable(forceUpdate) { - // invite, requestInvite, requestInviteResponse, inviteResponse, friendRequest - var notificationTable = this.notificationTable.data; - var i = notificationTable.length; - if (i > 0) { - if ( - notificationTable[i - 1].created_at === - this.sharedFeed.notificationTable.lastEntryDate && - forceUpdate === false - ) { - return; - } - this.sharedFeed.notificationTable.lastEntryDate = - notificationTable[i - 1].created_at; - } else { - return; - } - var bias = new Date(Date.now() - 86400000).toJSON(); // 24 hours - var wristArr = []; - var w = 0; - var wristFilter = this.sharedFeedFilters.wrist; - for (var i = notificationTable.length - 1; i > -1; i--) { - var ctx = notificationTable[i]; - if (ctx.created_at < bias) { - break; - } - if (ctx.senderUserId === API.currentUser.id) { - continue; - } - var isFriend = this.friends.has(ctx.senderUserId); - var isFavorite = this.localFavoriteFriends.has( - ctx.senderUserId - ); - if ( - w < 20 && - wristFilter[ctx.type] && - (wristFilter[ctx.type] === 'On' || - wristFilter[ctx.type] === 'Friends' || - (wristFilter[ctx.type] === 'VIP' && isFavorite)) - ) { - wristArr.push({ - ...ctx, - isFriend, - isFavorite - }); - ++w; - } - } - this.sharedFeed.notificationTable.wrist = wristArr; - this.sharedFeed.pendingUpdate = true; - }, - - updateSharedFeedFriendLogTable(forceUpdate) { - // TrustLevel, Friend, FriendRequest, Unfriend, DisplayName - var friendLog = this.friendLogTable.data; - var i = friendLog.length; - if (i > 0) { - if ( - friendLog[i - 1].created_at === - this.sharedFeed.friendLogTable.lastEntryDate && - forceUpdate === false - ) { - return; - } - this.sharedFeed.friendLogTable.lastEntryDate = - friendLog[i - 1].created_at; - } else { - return; - } - var bias = new Date(Date.now() - 86400000).toJSON(); // 24 hours - var wristArr = []; - var w = 0; - var wristFilter = this.sharedFeedFilters.wrist; - for (var i = friendLog.length - 1; i > -1; i--) { - var ctx = friendLog[i]; - if (ctx.created_at < bias) { - break; - } - if (ctx.type === 'FriendRequest') { - continue; - } - var isFriend = this.friends.has(ctx.userId); - var isFavorite = this.localFavoriteFriends.has(ctx.userId); - if ( - w < 20 && - wristFilter[ctx.type] && - (wristFilter[ctx.type] === 'On' || - wristFilter[ctx.type] === 'Friends' || - (wristFilter[ctx.type] === 'VIP' && isFavorite)) - ) { - wristArr.push({ - ...ctx, - isFriend, - isFavorite - }); - ++w; - } - } - this.sharedFeed.friendLogTable.wrist = wristArr; - this.sharedFeed.pendingUpdate = true; - }, - - updateSharedFeedModerationAgainstTable(forceUpdate) { - // Unblocked, Blocked, Muted, Unmuted - var moderationAgainst = this.moderationAgainstTable; - var i = moderationAgainst.length; - if (i > 0) { - if ( - moderationAgainst[i - 1].created_at === - this.sharedFeed.moderationAgainstTable.lastEntryDate && - forceUpdate === false - ) { - return; - } - this.sharedFeed.moderationAgainstTable.lastEntryDate = - moderationAgainst[i - 1].created_at; - } else { - return; - } - var bias = new Date(Date.now() - 86400000).toJSON(); // 24 hours - var wristArr = []; - var w = 0; - var wristFilter = this.sharedFeedFilters.wrist; - for (var i = moderationAgainst.length - 1; i > -1; i--) { - var ctx = moderationAgainst[i]; - if (ctx.created_at < bias) { - break; - } - var isFriend = this.friends.has(ctx.userId); - var isFavorite = this.localFavoriteFriends.has(ctx.userId); - // add tag colour - var tagColour = ''; - var tagRef = this.customUserTags.get(ctx.userId); - if (typeof tagRef !== 'undefined') { - tagColour = tagRef.colour; - } - if ( - w < 20 && - wristFilter[ctx.type] && - wristFilter[ctx.type] === 'On' - ) { - wristArr.push({ - ...ctx, - isFriend, - isFavorite, - tagColour - }); - ++w; - } - } - this.sharedFeed.moderationAgainstTable.wrist = wristArr; - this.sharedFeed.pendingUpdate = true; - } - }; -} diff --git a/src/classes/uiComponents.js b/src/classes/uiComponents.js deleted file mode 100644 index b2b6e286..00000000 --- a/src/classes/uiComponents.js +++ /dev/null @@ -1,512 +0,0 @@ -import Vue from 'vue'; -import VueMarkdown from 'vue-markdown'; -import { instanceRequest, userRequest } from '../api'; -import { hasGroupPermission } from '../composables/group/utils'; -import { parseLocation } from '../composables/instance/utils'; -import { $app, $t, API, baseClass } from './baseClass.js'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - init() { - Vue.component('vue-markdown', VueMarkdown); - - Vue.component('launch', { - template: - '', - props: { - location: String, - hideTooltips: Boolean - }, - methods: { - parse() { - this.$el.style.display = $app.checkCanInviteSelf( - this.location - ) - ? '' - : 'none'; - }, - confirm() { - this.$emit('show-launch-dialog', this.location); - } - }, - watch: { - location() { - this.parse(); - } - }, - mounted() { - this.parse(); - } - }); - - Vue.component('invite-yourself', { - template: - '', - props: { - location: String, - shortname: String - }, - methods: { - parse() { - this.$el.style.display = $app.checkCanInviteSelf( - this.location - ) - ? '' - : 'none'; - }, - confirm() { - this.selfInvite(this.location, this.shortname); - }, - selfInvite(location, shortName) { - const L = parseLocation(location); - if (!L.isRealInstance) { - return; - } - instanceRequest - .selfInvite({ - instanceId: L.instanceId, - worldId: L.worldId, - shortName - }) - .then((args) => { - this.$message({ - message: 'Self invite sent', - type: 'success' - }); - return args; - }); - } - }, - watch: { - location() { - this.parse(); - } - }, - mounted() { - this.parse(); - } - }); - - Vue.component('location-world', { - template: - '' + - '' + - '#{{ instanceName }} {{ accessTypeName }}' + - '({{ groupName }})' + - '' + - '', - props: { - locationobject: Object, - currentuserid: String, - worlddialogshortname: String, - grouphint: { - type: String, - default: '' - } - }, - data() { - return { - location: this.location, - instanceName: this.instanceName, - accessTypeName: this.accessTypeName, - region: this.region, - shortName: this.shortName, - isUnlocked: this.isUnlocked, - strict: this.strict, - groupName: this.groupName - }; - }, - methods: { - parse() { - this.location = this.locationobject.tag; - this.instanceName = this.locationobject.instanceName; - this.accessTypeName = this.locationobject.accessTypeName; - this.strict = this.locationobject.strict; - this.shortName = this.locationobject.shortName; - - this.isUnlocked = false; - if ( - (this.worlddialogshortname && - this.locationobject.shortName && - this.worlddialogshortname === - this.locationobject.shortName) || - this.currentuserid === this.locationobject.userId - ) { - this.isUnlocked = true; - } - - this.region = this.locationobject.region; - if (!this.region) { - this.region = 'us'; - } - - this.groupName = ''; - if (this.grouphint) { - this.groupName = this.grouphint; - } else if (this.locationobject.groupId) { - this.groupName = this.locationobject.groupId; - $app.getGroupName(this.locationobject.groupId).then( - (groupName) => { - this.groupName = groupName; - } - ); - } - }, - showLaunchDialog() { - this.$emit( - 'show-launch-dialog', - this.location, - this.shortName - ); - }, - showGroupDialog() { - if (!this.location) { - return; - } - var L = parseLocation(this.location); - if (!L.groupId) { - return; - } - $app.showGroupDialog(L.groupId); - } - }, - watch: { - locationobject() { - this.parse(); - } - }, - created() { - this.parse(); - } - }); - - Vue.component('last-join', { - template: - '' + - '' + - '
' + - '{{ $t("dialog.user.info.last_join") }} ' + - '
' + - '' + - '
' + - '
', - props: { - location: String, - currentlocation: String - }, - data() { - return { - lastJoin: this.lastJoin - }; - }, - methods: { - parse() { - this.lastJoin = $app.instanceJoinHistory.get(this.location); - } - }, - watch: { - location() { - this.parse(); - }, - currentlocation() { - this.parse(); - } - }, - created() { - this.parse(); - } - }); - - Vue.component('instance-info', { - template: - '
' + - '' + - '
' + - '' + - '' + - 'PC: {{ platforms.standalonewindows }}
' + - 'Android: {{ platforms.android }}
' + - '{{ $t("dialog.user.info.instance_game_version") }} {{ gameServerVersion }}
' + - '{{ $t("dialog.user.info.instance_queuing_enabled") }}
' + - '{{ $t("dialog.user.info.instance_disabled_content") }} {{ disabledContentSettings }}
' + - '{{ $t("dialog.user.info.instance_users") }}
' + - '' + - '
' + - '' + - '
' + - '{{ occupants }}/{{ capacity }}' + - '({{ friendcount }})' + - '{{ $t("dialog.user.info.instance_full") }}' + - '{{ $t("dialog.user.info.instance_hard_closed") }}' + - '{{ $t("dialog.user.info.instance_closed") }}' + - '{{ $t("dialog.user.info.instance_queue") }} {{ queueSize }}' + - '{{ $t("dialog.user.info.instance_age_gated") }}' + - '
', - props: { - location: String, - instance: Object, - friendcount: Number, - updateelement: Number - }, - data() { - return { - isValidInstance: this.isValidInstance, - isFull: this.isFull, - isClosed: this.isClosed, - isHardClosed: this.isHardClosed, - closedAt: this.closedAt, - occupants: this.occupants, - capacity: this.capacity, - queueSize: this.queueSize, - queueEnabled: this.queueEnabled, - platforms: this.platforms, - userList: this.userList, - gameServerVersion: this.gameServerVersion, - canCloseInstance: this.canCloseInstance - }; - }, - methods: { - parse() { - this.isValidInstance = false; - this.isFull = false; - this.isClosed = false; - this.isHardClosed = false; - this.closedAt = ''; - this.occupants = 0; - this.capacity = 0; - this.queueSize = 0; - this.queueEnabled = false; - this.platforms = []; - this.userList = []; - this.gameServerVersion = ''; - this.canCloseInstance = false; - this.isAgeGated = false; - this.disabledContentSettings = ''; - if ( - !this.location || - !this.instance || - Object.keys(this.instance).length === 0 - ) { - return; - } - this.isValidInstance = true; - this.isFull = - typeof this.instance.hasCapacityForYou !== - 'undefined' && !this.instance.hasCapacityForYou; - if (this.instance.closedAt) { - this.isClosed = true; - this.closedAt = this.instance.closedAt; - } - this.isHardClosed = this.instance.hardClose === true; - this.occupants = this.instance.userCount; - if (this.location === $app.lastLocation.location) { - // use gameLog for occupants when in same location - this.occupants = $app.lastLocation.playerList.size; - } - this.capacity = this.instance.capacity; - this.gameServerVersion = this.instance.gameServerVersion; - this.queueSize = this.instance.queueSize; - if (this.instance.platforms) { - this.platforms = this.instance.platforms; - } - if (this.instance.users) { - this.userList = this.instance.users; - } - if (this.instance.ownerId === API.currentUser.id) { - this.canCloseInstance = true; - } else if (this.instance?.ownerId?.startsWith('grp_')) { - // check group perms - var groupId = this.instance.ownerId; - var group = API.cachedGroups.get(groupId); - this.canCloseInstance = hasGroupPermission( - group, - 'group-instance-moderate' - ); - } - this.isAgeGated = this.instance.ageGate === true; - if (this.location && this.location.includes('~ageGate')) { - // dumb workaround for API not returning `ageGate` - this.isAgeGated = true; - } - if ( - this.instance.$disabledContentSettings && - this.instance.$disabledContentSettings.length - ) { - this.disabledContentSettings = - this.instance.$disabledContentSettings.join(', '); - } - }, - showUserDialog(userId) { - this.showUserDialog(userId); - } - }, - watch: { - updateelement() { - this.parse(); - }, - location() { - this.parse(); - }, - friendcount() { - this.parse(); - } - }, - created() { - this.parse(); - } - }); - - Vue.component('avatar-info', { - template: - '
' + - '{{ avatarName }}' + - '{{ avatarType }}' + - '{{ avatarTags }}' + - '
', - props: { - imageurl: String, - userid: String, - hintownerid: String, - hintavatarname: String, - avatartags: Array - }, - data() { - return { - avatarName: this.avatarName, - avatarType: this.avatarType, - avatarTags: this.avatarTags, - color: this.color - }; - }, - methods: { - async parse() { - this.ownerId = ''; - this.avatarName = ''; - this.avatarType = ''; - this.color = ''; - this.avatarTags = ''; - if (!this.imageurl) { - this.avatarName = '-'; - } else if (this.hintownerid) { - this.avatarName = this.hintavatarname; - this.ownerId = this.hintownerid; - } else { - try { - var avatarInfo = await $app.getAvatarName( - this.imageurl - ); - this.avatarName = avatarInfo.avatarName; - this.ownerId = avatarInfo.ownerId; - } catch (err) {} - } - if (typeof this.userid === 'undefined' || !this.ownerId) { - this.color = ''; - this.avatarType = ''; - } else if (this.ownerId === this.userid) { - this.color = 'avatar-info-own'; - this.avatarType = '(own)'; - } else { - this.color = 'avatar-info-public'; - this.avatarType = '(public)'; - } - if (typeof this.avatartags === 'object') { - var tagString = ''; - for (var i = 0; i < this.avatartags.length; i++) { - var tagName = this.avatartags[i].replace( - 'content_', - '' - ); - tagString += tagName; - if (i < this.avatartags.length - 1) { - tagString += ', '; - } - } - this.avatarTags = tagString; - } - }, - confirm() { - if (!this.imageurl) { - return; - } - $app.showAvatarAuthorDialog( - this.userid, - this.ownerId, - this.imageurl - ); - } - }, - watch: { - imageurl() { - this.parse(); - }, - userid() { - this.parse(); - }, - avatartags() { - this.parse(); - } - }, - mounted() { - this.parse(); - } - }); - - Vue.component('display-name', { - template: - '{{ username }}', - props: { - userid: String, - location: String, - forceUpdateKey: Number, - hint: { - type: String, - default: '' - } - }, - data() { - return { - username: this.username - }; - }, - methods: { - async parse() { - this.username = this.userid; - if (this.hint) { - this.username = this.hint; - } else if (this.userid) { - var args = await userRequest.getCachedUser({ - userId: this.userid - }); - } - if ( - typeof args !== 'undefined' && - typeof args.json !== 'undefined' && - typeof args.json.displayName !== 'undefined' - ) { - this.username = args.json.displayName; - } - }, - showUserDialog() { - $app.showUserDialog(this.userid); - } - }, - watch: { - location() { - this.parse(); - }, - forceUpdateKey() { - this.parse(); - }, - userid() { - this.parse(); - } - }, - mounted() { - this.parse(); - } - }); - } -} diff --git a/src/classes/updateLoop.js b/src/classes/updateLoop.js deleted file mode 100644 index 5ad701a1..00000000 --- a/src/classes/updateLoop.js +++ /dev/null @@ -1,122 +0,0 @@ -import * as workerTimers from 'worker-timers'; -import { baseClass, $app, API } from './baseClass.js'; -import { groupRequest } from '../api/index.js'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - init() { - API.$on('LOGIN', function () { - $app.nextCurrentUserRefresh = 300; - $app.nextFriendsRefresh = 3600; - $app.nextGroupInstanceRefresh = 0; - }); - } - - _data = { - nextCurrentUserRefresh: 300, - nextFriendsRefresh: 3600, - nextGroupInstanceRefresh: 0, - nextAppUpdateCheck: 3600, - ipcTimeout: 0, - nextClearVRCXCacheCheck: 0, - nextDiscordUpdate: 0, - nextAutoStateChange: 0, - nextGetLogCheck: 0, - nextGameRunningCheck: 0, - nextDatabaseOptimize: 3600 - }; - - _methods = { - async updateLoop() { - try { - if (API.isLoggedIn === true) { - if (--this.nextCurrentUserRefresh <= 0) { - this.nextCurrentUserRefresh = 300; // 5min - API.getCurrentUser(); - } - if (--this.nextFriendsRefresh <= 0) { - this.nextFriendsRefresh = 3600; // 1hour - this.refreshFriendsList(); - this.updateStoredUser(API.currentUser); - if (this.isGameRunning) { - API.refreshPlayerModerations(); - } - } - if (--this.nextGroupInstanceRefresh <= 0) { - if (this.friendLogInitStatus) { - this.nextGroupInstanceRefresh = 300; // 5min - groupRequest.getUsersGroupInstances(); - } - AppApi.CheckGameRunning(); - } - if (--this.nextAppUpdateCheck <= 0) { - this.nextAppUpdateCheck = 3600; // 1hour - if (this.autoUpdateVRCX !== 'Off') { - this.checkForVRCXUpdate(); - } - } - if (--this.ipcTimeout <= 0) { - this.ipcEnabled = false; - } - if ( - --this.nextClearVRCXCacheCheck <= 0 && - this.clearVRCXCacheFrequency > 0 - ) { - this.nextClearVRCXCacheCheck = - this.clearVRCXCacheFrequency / 2; - this.clearVRCXCache(); - } - if (--this.nextDiscordUpdate <= 0) { - this.nextDiscordUpdate = 3; - if (this.discordActive) { - this.updateDiscord(); - } - } - if (--this.nextAutoStateChange <= 0) { - this.nextAutoStateChange = 3; - this.updateAutoStateChange(); - } - if ( - (this.isRunningUnderWine || LINUX) && - --this.nextGetLogCheck <= 0 - ) { - this.nextGetLogCheck = 0.5; - const logLines = await LogWatcher.GetLogLines(); - if (logLines) { - logLines.forEach((logLine) => { - $app.addGameLogEvent(logLine); - }); - } - } - if ( - (this.isRunningUnderWine || LINUX) && - --this.nextGameRunningCheck <= 0 - ) { - if (LINUX) { - this.nextGameRunningCheck = 1; - $app.updateIsGameRunning( - await AppApi.IsGameRunning(), - await AppApi.IsSteamVRRunning(), - false - ); - } else { - this.nextGameRunningCheck = 3; - AppApi.CheckGameRunning(); - } - } - if (--this.nextDatabaseOptimize <= 0) { - this.nextDatabaseOptimize = 86400; // 1 day - database.optimize(); - } - } - } catch (err) { - API.isRefreshFriendsLoading = false; - console.error(err); - } - workerTimers.setTimeout(() => this.updateLoop(), 1000); - } - }; -} diff --git a/src/classes/userNotes.js b/src/classes/userNotes.js deleted file mode 100644 index 1c252996..00000000 --- a/src/classes/userNotes.js +++ /dev/null @@ -1,118 +0,0 @@ -import { userRequest } from '../api'; -import database from '../service/database.js'; -import utils from '../classes/utils'; -import * as workerTimers from 'worker-timers'; - -const userNotes = { - lastNoteCheck: null, - lastDbNoteDate: null, - notes: new Map(), - - async init() { - this.lastNoteCheck = new Date(); - this.lastDbNoteDate = null; - this.notes.clear(); - try { - // todo: get users from store - const users = window.API.cachedUsers; - const dbNotes = await database.getAllUserNotes(); - for (const note of dbNotes) { - this.notes.set(note.userId, note.note); - const user = users.get(note.userId); - if (user) { - user.note = note.note; - } - if ( - !this.lastDbNoteDate || - this.lastDbNoteDate < note.createdAt - ) { - this.lastDbNoteDate = note.createdAt; - } - } - await this.getLatestUserNotes(); - } catch (error) { - console.error('Error initializing user notes:', error); - } - }, - - async getLatestUserNotes() { - this.lastNoteCheck = new Date(); - const params = { - offset: 0, - n: 10 // start light - }; - const newNotes = new Map(); - let done = false; - try { - for (let i = 0; i < 100; i++) { - params.offset = i * params.n; - const args = await userRequest.getUserNotes(params); - for (const note of args.json) { - if ( - this.lastDbNoteDate && - this.lastDbNoteDate > note.createdAt - ) { - done = true; - } - if ( - !this.lastDbNoteDate || - this.lastDbNoteDate < note.createdAt - ) { - this.lastDbNoteDate = note.createdAt; - } - note.note = utils.replaceBioSymbols(note.note); - newNotes.set(note.targetUserId, note); - } - if (done || args.json.length === 0) { - break; - } - params.n = 100; // crank it after first run - await new Promise((resolve) => { - workerTimers.setTimeout(resolve, 1000); - }); - } - } catch (error) { - console.error('Error fetching user notes:', error); - } - // todo: get users from store - const users = window.API.cachedUsers; - - for (const note of newNotes.values()) { - const newNote = { - userId: note.targetUserId, - displayName: note.targetUser?.displayName || note.targetUserId, - note: note.note, - createdAt: note.createdAt - }; - await database.addUserNote(newNote); - this.notes.set(note.targetUserId, note.note); - const user = users.get(note.targetUserId); - if (user) { - user.note = note.note; - } - } - }, - - async checkNote(userId, newNote) { - // last check was more than than 5 minutes ago - if ( - !this.lastNoteCheck || - this.lastNoteCheck.getTime() + 5 * 60 * 1000 > Date.now() - ) { - return; - } - const existingNote = this.notes.get(userId); - if (typeof existingNote !== 'undefined' && !newNote) { - console.log('deleting note', userId); - this.notes.delete(userId); - await database.deleteUserNote(userId); - return; - } - if (typeof existingNote === 'undefined' || existingNote !== newNote) { - console.log('detected note change', userId, newNote); - await this.getLatestUserNotes(); - } - } -}; - -export { userNotes }; diff --git a/src/classes/utils.js b/src/classes/utils.js deleted file mode 100644 index db2888b3..00000000 --- a/src/classes/utils.js +++ /dev/null @@ -1,302 +0,0 @@ -let echarts = null; - -const _utils = { - removeFromArray(array, item) { - var { length } = array; - for (var i = 0; i < length; ++i) { - if (array[i] === item) { - array.splice(i, 1); - return true; - } - } - return false; - }, - arraysMatch(a, b) { - if (!Array.isArray(a) || !Array.isArray(b)) { - return false; - } - return ( - a.length === b.length && - a.every( - (element, index) => - JSON.stringify(element) === JSON.stringify(b[index]) - ) - ); - }, - moveArrayItem(array, fromIndex, toIndex) { - if (!Array.isArray(array) || fromIndex === toIndex) { - return; - } - if (fromIndex < 0 || fromIndex >= array.length) { - return; - } - if (toIndex < 0 || toIndex >= array.length) { - return; - } - const item = array[fromIndex]; - array.splice(fromIndex, 1); - array.splice(toIndex, 0, item); - }, - escapeTag(tag) { - var s = String(tag); - return s.replace(/["&'<>]/g, (c) => `&#${c.charCodeAt(0)};`); - }, - escapeTagRecursive(obj) { - if (typeof obj === 'string') { - return this.escapeTag(obj); - } - if (typeof obj === 'object') { - for (var key in obj) { - obj[key] = this.escapeTagRecursive(obj[key]); - } - } - return obj; - }, - timeToText(sec, isNeedSeconds = false) { - let n = Number(sec); - if (isNaN(n)) { - return this.escapeTag(sec); - } - n = Math.floor(n / 1000); - const arr = []; - if (n < 0) { - n = -n; - } - if (n >= 86400) { - arr.push(`${Math.floor(n / 86400)}d`); - n %= 86400; - } - if (n >= 3600) { - arr.push(`${Math.floor(n / 3600)}h`); - n %= 3600; - } - if (n >= 60) { - arr.push(`${Math.floor(n / 60)}m`); - n %= 60; - } - if (isNeedSeconds || (arr.length === 0 && n < 60)) { - arr.push(`${n}s`); - } - return arr.join(' '); - }, - textToHex(text) { - var s = String(text); - return s - .split('') - .map((c) => c.charCodeAt(0).toString(16)) - .join(' '); - }, - commaNumber(num) { - if (!num) { - return '0'; - } - var s = String(Number(num)); - return s.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); - }, - buildTreeData(json) { - var node = []; - for (var key in json) { - if (key[0] === '$') { - continue; - } - var value = json[key]; - if (Array.isArray(value) && value.length === 0) { - node.push({ - key, - value: '[]' - }); - } else if ( - value === Object(value) && - Object.keys(value).length === 0 - ) { - node.push({ - key, - value: '{}' - }); - } else if (Array.isArray(value)) { - node.push({ - children: value.map((val, idx) => { - if (val === Object(val)) { - return { - children: this.buildTreeData(val), - key: idx - }; - } - return { - key: idx, - value: val - }; - }), - key - }); - } else if (value === Object(value)) { - node.push({ - children: this.buildTreeData(value), - key - }); - } else { - node.push({ - key, - value: String(value) - }); - } - } - node.sort(function (a, b) { - var A = String(a.key).toUpperCase(); - var B = String(b.key).toUpperCase(); - if (A < B) { - return -1; - } - if (A > B) { - return 1; - } - return 0; - }); - return node; - }, - // descending - compareByCreatedAt(a, b) { - if ( - typeof a.created_at !== 'string' || - typeof b.created_at !== 'string' - ) { - return 0; - } - var A = a.created_at.toUpperCase(); - var B = b.created_at.toUpperCase(); - if (A < B) { - return 1; - } - if (A > B) { - return -1; - } - return 0; - }, - // lazy load echarts - loadEcharts() { - if (echarts) { - return Promise.resolve(echarts); - } - return import('echarts').then((module) => { - echarts = module; - return echarts; - }); - }, - // CJK character in Japanese, Korean, Chinese are different - // so change font-family order when users change language to display CJK character correctly - changeCJKorder(lang) { - const otherFonts = window - .getComputedStyle(document.body) - .fontFamily.split(',') - .filter((item) => !item.includes('Noto Sans')) - .join(', '); - const notoSans = 'Noto Sans'; - - const fontFamilies = { - ja_JP: ['JP', 'KR', 'TC', 'SC'], - ko: ['KR', 'JP', 'TC', 'SC'], - zh_TW: ['TC', 'JP', 'KR', 'SC'], - zh_CN: ['SC', 'JP', 'KR', 'TC'] - }; - - if (fontFamilies[lang]) { - const CJKFamily = fontFamilies[lang] - .map((item) => `${notoSans} ${item}`) - .join(', '); - document.body.style.fontFamily = `${CJKFamily}, ${otherFonts}`; - } - }, - localeIncludes(str, search, comparer) { - // These checks are stolen from https://stackoverflow.com/a/69623589/11030436 - if (search === '') { - return true; - } else if (!str || !search) { - return false; - } - const strObj = String(str); - const searchObj = String(search); - - if (strObj.length === 0) { - return false; - } - - if (searchObj.length > strObj.length) { - return false; - } - - // Now simply loop through each substring and compare them - for (let i = 0; i < str.length - searchObj.length + 1; i++) { - const substr = strObj.substring(i, i + searchObj.length); - if (comparer.compare(substr, searchObj) === 0) { - return true; - } - } - return false; - }, - compareByName(a, b) { - if (typeof a.name !== 'string' || typeof b.name !== 'string') { - return 0; - } - return a.name.localeCompare(b.name); - }, - replaceBioSymbols(text) { - if (!text) { - return ''; - } - var symbolList = { - '@': '@', - '#': '#', - $: '$', - '%': '%', - '&': '&', - '=': '=', - '+': '+', - '/': '⁄', - '\\': '\', - ';': ';', - ':': '˸', - ',': '‚', - '?': '?', - '!': 'ǃ', - '"': '"', - '<': '≺', - '>': '≻', - '.': '․', - '^': '^', - '{': '{', - '}': '}', - '[': '[', - ']': ']', - '(': '(', - ')': ')', - '|': '|', - '*': '∗' - }; - var newText = text; - for (var key in symbolList) { - var regex = new RegExp(symbolList[key], 'g'); - newText = newText.replace(regex, key); - } - return newText.replace(/ {1,}/g, ' ').trimRight(); - }, - // descending - compareByUpdatedAt(a, b) { - if ( - typeof a.updated_at !== 'string' || - typeof b.updated_at !== 'string' - ) { - return 0; - } - var A = a.updated_at.toUpperCase(); - var B = b.updated_at.toUpperCase(); - if (A < B) { - return 1; - } - if (A > B) { - return -1; - } - return 0; - } -}; - -export default _utils; diff --git a/src/classes/vrcRegistry.js b/src/classes/vrcRegistry.js deleted file mode 100644 index 7a17f892..00000000 --- a/src/classes/vrcRegistry.js +++ /dev/null @@ -1,121 +0,0 @@ -import configRepository from '../service/config.js'; -import { baseClass, $t, $utils } from './baseClass.js'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - init() {} - - _data = {}; - - _methods = { - async backupVrcRegistry(name) { - var regJson; - if (LINUX) { - regJson = await AppApi.GetVRChatRegistryJson(); - regJson = JSON.parse(regJson); - } else { - regJson = await AppApi.GetVRChatRegistry(); - } - var newBackup = { - name, - date: new Date().toJSON(), - data: regJson - }; - var backupsJson = await configRepository.getString( - 'VRCX_VRChatRegistryBackups' - ); - if (!backupsJson) { - backupsJson = JSON.stringify([]); - } - var backups = JSON.parse(backupsJson); - backups.push(newBackup); - await configRepository.setString( - 'VRCX_VRChatRegistryBackups', - JSON.stringify(backups) - ); - // await this.updateRegistryBackupDialog(); - }, - - // Because it is a startup func, it is not integrated into RegistryBackupDialog.vue now - // func backupVrcRegistry is also split up - async checkAutoBackupRestoreVrcRegistry() { - if (!this.vrcRegistryAutoBackup) { - return; - } - - // check for auto restore - var hasVRChatRegistryFolder = - await AppApi.HasVRChatRegistryFolder(); - if (!hasVRChatRegistryFolder) { - var lastBackupDate = await configRepository.getString( - 'VRCX_VRChatRegistryLastBackupDate' - ); - var lastRestoreCheck = await configRepository.getString( - 'VRCX_VRChatRegistryLastRestoreCheck' - ); - if ( - !lastBackupDate || - (lastRestoreCheck && - lastBackupDate && - lastRestoreCheck === lastBackupDate) - ) { - // only ask to restore once and when backup is present - return; - } - // popup message about auto restore - this.$alert( - $t('dialog.registry_backup.restore_prompt'), - $t('dialog.registry_backup.header') - ); - this.showRegistryBackupDialog(); - await AppApi.FocusWindow(); - await configRepository.setString( - 'VRCX_VRChatRegistryLastRestoreCheck', - lastBackupDate - ); - } else { - await this.autoBackupVrcRegistry(); - } - }, - - async autoBackupVrcRegistry() { - var date = new Date(); - var lastBackupDate = await configRepository.getString( - 'VRCX_VRChatRegistryLastBackupDate' - ); - if (lastBackupDate) { - var lastBackup = new Date(lastBackupDate); - var diff = date.getTime() - lastBackup.getTime(); - var diffDays = Math.floor(diff / (1000 * 60 * 60 * 24)); - if (diffDays < 7) { - return; - } - } - var backupsJson = await configRepository.getString( - 'VRCX_VRChatRegistryBackups' - ); - if (!backupsJson) { - backupsJson = JSON.stringify([]); - } - var backups = JSON.parse(backupsJson); - backups.forEach((backup) => { - if (backup.name === 'Auto Backup') { - // remove old auto backup - $utils.removeFromArray(backups, backup); - } - }); - await configRepository.setString( - 'VRCX_VRChatRegistryBackups', - JSON.stringify(backups) - ); - this.backupVrcRegistry('Auto Backup'); - await configRepository.setString( - 'VRCX_VRChatRegistryLastBackupDate', - date.toJSON() - ); - } - }; -} diff --git a/src/classes/vrcxNotifications.js b/src/classes/vrcxNotifications.js deleted file mode 100644 index 6de31fb3..00000000 --- a/src/classes/vrcxNotifications.js +++ /dev/null @@ -1,1753 +0,0 @@ -import { userRequest } from '../api'; -import { displayLocation } from '../composables/instance/utils'; -import { extractFileId, extractFileVersion } from '../composables/shared/utils'; -import { $app, API, baseClass } from './baseClass.js'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - _data = { - notyMap: [] - }; - - _methods = { - queueGameLogNoty(noty) { - // remove join/leave notifications when switching worlds - if ( - noty.type === 'OnPlayerJoined' || - noty.type === 'BlockedOnPlayerJoined' || - noty.type === 'MutedOnPlayerJoined' - ) { - var bias = this.lastLocation.date + 30 * 1000; // 30 secs - if (Date.parse(noty.created_at) <= bias) { - return; - } - } - if ( - noty.type === 'OnPlayerLeft' || - noty.type === 'BlockedOnPlayerLeft' || - noty.type === 'MutedOnPlayerLeft' - ) { - var bias = this.lastLocationDestinationTime + 5 * 1000; // 5 secs - if (Date.parse(noty.created_at) <= bias) { - return; - } - } - if ( - noty.type === 'Notification' || - noty.type === 'LocationDestination' - // skip unused entries - ) { - return; - } - if (noty.type === 'VideoPlay') { - if (!noty.videoName) { - // skip video without name - return; - } - noty.notyName = noty.videoName; - if (noty.displayName) { - // add requester's name to noty - noty.notyName = `${noty.videoName} (${noty.displayName})`; - } - } - if ( - noty.type !== 'VideoPlay' && - noty.displayName === API.currentUser.displayName - ) { - // remove current user - return; - } - noty.isFriend = false; - noty.isFavorite = false; - if (noty.userId) { - noty.isFriend = this.friends.has(noty.userId); - noty.isFavorite = this.localFavoriteFriends.has(noty.userId); - } else if (noty.displayName) { - for (var ref of API.cachedUsers.values()) { - if (ref.displayName === noty.displayName) { - noty.isFriend = this.friends.has(ref.id); - noty.isFavorite = this.localFavoriteFriends.has(ref.id); - break; - } - } - } - var notyFilter = this.sharedFeedFilters.noty; - if ( - notyFilter[noty.type] && - (notyFilter[noty.type] === 'On' || - notyFilter[noty.type] === 'Everyone' || - (notyFilter[noty.type] === 'Friends' && noty.isFriend) || - (notyFilter[noty.type] === 'VIP' && noty.isFavorite)) - ) { - this.playNoty(noty); - } - }, - - queueFeedNoty(noty) { - if (noty.type === 'Avatar') { - return; - } - // hide private worlds from feed - if ( - this.hidePrivateFromFeed && - noty.type === 'GPS' && - noty.location === 'private' - ) { - return; - } - noty.isFriend = this.friends.has(noty.userId); - noty.isFavorite = this.localFavoriteFriends.has(noty.userId); - var notyFilter = this.sharedFeedFilters.noty; - if ( - notyFilter[noty.type] && - (notyFilter[noty.type] === 'Everyone' || - (notyFilter[noty.type] === 'Friends' && noty.isFriend) || - (notyFilter[noty.type] === 'VIP' && noty.isFavorite)) - ) { - this.playNoty(noty); - } - }, - - queueNotificationNoty(noty) { - noty.isFriend = this.friends.has(noty.senderUserId); - noty.isFavorite = this.localFavoriteFriends.has(noty.senderUserId); - var notyFilter = this.sharedFeedFilters.noty; - if ( - notyFilter[noty.type] && - (notyFilter[noty.type] === 'On' || - notyFilter[noty.type] === 'Friends' || - (notyFilter[noty.type] === 'VIP' && noty.isFavorite)) - ) { - this.playNoty(noty); - } - }, - - queueFriendLogNoty(noty) { - if (noty.type === 'FriendRequest') { - return; - } - noty.isFriend = this.friends.has(noty.userId); - noty.isFavorite = this.localFavoriteFriends.has(noty.userId); - var notyFilter = this.sharedFeedFilters.noty; - if ( - notyFilter[noty.type] && - (notyFilter[noty.type] === 'On' || - notyFilter[noty.type] === 'Friends' || - (notyFilter[noty.type] === 'VIP' && noty.isFavorite)) - ) { - this.playNoty(noty); - } - }, - - queueModerationNoty(noty) { - noty.isFriend = false; - noty.isFavorite = false; - if (noty.userId) { - noty.isFriend = this.friends.has(noty.userId); - noty.isFavorite = this.localFavoriteFriends.has(noty.userId); - } - var notyFilter = this.sharedFeedFilters.noty; - if (notyFilter[noty.type] && notyFilter[noty.type] === 'On') { - this.playNoty(noty); - } - }, - - playNoty(noty) { - if ( - API.currentUser.status === 'busy' || - !this.friendLogInitStatus - ) { - return; - } - var displayName = ''; - if (noty.displayName) { - displayName = noty.displayName; - } else if (noty.senderUsername) { - displayName = noty.senderUsername; - } else if (noty.sourceDisplayName) { - displayName = noty.sourceDisplayName; - } - if (displayName) { - // don't play noty twice - var notyId = `${noty.type},${displayName}`; - if ( - this.notyMap[notyId] && - this.notyMap[notyId] >= noty.created_at - ) { - return; - } - this.notyMap[notyId] = noty.created_at; - } - var bias = new Date(Date.now() - 60000).toJSON(); - if (noty.created_at < bias) { - // don't play noty if it's over 1min old - return; - } - - const notiConditions = { - Always: () => true, - 'Inside VR': () => this.isSteamVRRunning, - 'Outside VR': () => !this.isSteamVRRunning, - 'Game Closed': () => !this.isGameRunning, // Also known as "Outside VRChat" - 'Game Running': () => this.isGameRunning, // Also known as "Inside VRChat" - 'Desktop Mode': () => this.isGameNoVR && this.isGameRunning, - AFK: () => - this.afkDesktopToast && - this.isHmdAfk && - this.isGameRunning && - !this.isGameNoVR - }; - - const playNotificationTTS = - notiConditions[this.notificationTTS]?.(); - const playDesktopToast = - notiConditions[this.desktopToast]?.() || - notiConditions['AFK'](); - - const playOverlayToast = notiConditions[this.overlayToast]?.(); - const playOverlayNotification = - this.overlayNotifications && playOverlayToast; - const playXSNotification = this.xsNotifications && playOverlayToast; - const playOvrtHudNotifications = - this.ovrtHudNotifications && playOverlayToast; - const playOvrtWristNotifications = - this.ovrtWristNotifications && playOverlayToast; - - var message = ''; - if (noty.title) { - message = `${noty.title}, ${noty.message}`; - } else if (noty.message) { - message = noty.message; - } - var messageList = [ - 'inviteMessage', - 'requestMessage', - 'responseMessage' - ]; - for (var k = 0; k < messageList.length; k++) { - if ( - typeof noty.details !== 'undefined' && - typeof noty.details[messageList[k]] !== 'undefined' - ) { - message = `, ${noty.details[messageList[k]]}`; - } - } - if (playNotificationTTS) { - this.playNotyTTS(noty, displayName, message); - } - if ( - playDesktopToast || - playXSNotification || - playOvrtHudNotifications || - playOvrtWristNotifications || - playOverlayNotification - ) { - if (this.imageNotifications) { - this.notySaveImage(noty).then((image) => { - if (playXSNotification) { - this.displayXSNotification(noty, message, image); - } - if ( - playOvrtHudNotifications || - playOvrtWristNotifications - ) { - this.displayOvrtNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - noty, - message, - image - ); - } - if (playDesktopToast) { - this.displayDesktopToast(noty, message, image); - } - if (playOverlayNotification) { - this.displayOverlayNotification( - noty, - message, - image - ); - } - }); - } else { - if (playXSNotification) { - this.displayXSNotification(noty, message, ''); - } - if ( - playOvrtHudNotifications || - playOvrtWristNotifications - ) { - this.displayOvrtNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - noty, - message, - '' - ); - } - if (playDesktopToast) { - this.displayDesktopToast(noty, message, ''); - } - if (playOverlayNotification) { - this.displayOverlayNotification(noty, message, ''); - } - } - } - }, - - getUserIdFromNoty(noty) { - var userId = ''; - if (noty.userId) { - userId = noty.userId; - } else if (noty.senderUserId) { - userId = noty.senderUserId; - } else if (noty.sourceUserId) { - userId = noty.sourceUserId; - } else if (noty.displayName) { - for (var ref of API.cachedUsers.values()) { - if (ref.displayName === noty.displayName) { - userId = ref.id; - break; - } - } - } - return userId; - }, - - async notyGetImage(noty) { - var imageUrl = ''; - var userId = this.getUserIdFromNoty(noty); - - if (noty.thumbnailImageUrl) { - imageUrl = noty.thumbnailImageUrl; - } else if (noty.details && noty.details.imageUrl) { - imageUrl = noty.details.imageUrl; - } else if (noty.imageUrl) { - imageUrl = noty.imageUrl; - } else if (userId && !userId.startsWith('grp_')) { - imageUrl = await userRequest - .getCachedUser({ - userId - }) - .catch((err) => { - console.error(err); - return ''; - }) - .then((args) => { - if (!args.json) { - return ''; - } - if ( - this.displayVRCPlusIconsAsAvatar && - args.json.userIcon - ) { - return args.json.userIcon; - } - if (args.json.profilePicOverride) { - return args.json.profilePicOverride; - } - return args.json.currentAvatarThumbnailImageUrl; - }); - } - return imageUrl; - }, - - async notySaveImage(noty) { - var imageUrl = await this.notyGetImage(noty); - var fileId = extractFileId(imageUrl); - var fileVersion = extractFileVersion(imageUrl); - var imageLocation = ''; - try { - if (fileId && fileVersion) { - imageLocation = await AppApi.GetImage( - imageUrl, - fileId, - fileVersion - ); - } else if (imageUrl) { - fileVersion = imageUrl.split('/').pop(); // 1416226261.thumbnail-500.png - fileId = fileVersion.split('.').shift(); // 1416226261 - imageLocation = await AppApi.GetImage( - imageUrl, - fileId, - fileVersion - ); - } - } catch (err) { - console.error(imageUrl, err); - } - return imageLocation; - }, - - displayOverlayNotification(noty, message, imageFile) { - var image = ''; - if (imageFile) { - image = `file:///${imageFile}`; - } - AppApi.ExecuteVrOverlayFunction( - 'playNoty', - JSON.stringify({ noty, message, image }) - ); - }, - - async playNotyTTS(noty, displayName, message) { - if (this.notificationTTSNickName) { - var userId = this.getUserIdFromNoty(noty); - var memo = await $app.getUserMemo(userId); - if (memo.memo) { - var array = memo.memo.split('\n'); - var nickName = array[0]; - displayName = nickName; - } - } - switch (noty.type) { - case 'OnPlayerJoined': - this.speak(`${displayName} has joined`); - break; - case 'OnPlayerLeft': - this.speak(`${displayName} has left`); - break; - case 'OnPlayerJoining': - this.speak(`${displayName} is joining`); - break; - case 'GPS': - this.speak( - `${displayName} is in ${displayLocation( - noty.location, - noty.worldName, - noty.groupName - )}` - ); - break; - case 'Online': - var locationName = ''; - if (noty.worldName) { - locationName = ` to ${displayLocation( - noty.location, - noty.worldName, - noty.groupName - )}`; - } - this.speak(`${displayName} has logged in${locationName}`); - break; - case 'Offline': - this.speak(`${displayName} has logged out`); - break; - case 'Status': - this.speak( - `${displayName} status is now ${noty.status} ${noty.statusDescription}` - ); - break; - case 'invite': - this.speak( - `${displayName} has invited you to ${displayLocation( - noty.details.worldId, - noty.details.worldName, - noty.groupName - )}${message}` - ); - break; - case 'requestInvite': - this.speak( - `${displayName} has requested an invite${message}` - ); - break; - case 'inviteResponse': - this.speak( - `${displayName} has responded to your invite${message}` - ); - break; - case 'requestInviteResponse': - this.speak( - `${displayName} has responded to your invite request${message}` - ); - break; - case 'friendRequest': - this.speak(`${displayName} has sent you a friend request`); - break; - case 'Friend': - this.speak(`${displayName} is now your friend`); - break; - case 'Unfriend': - this.speak(`${displayName} is no longer your friend`); - break; - case 'TrustLevel': - this.speak( - `${displayName} trust level is now ${noty.trustLevel}` - ); - break; - case 'DisplayName': - this.speak( - `${noty.previousDisplayName} changed their name to ${noty.displayName}` - ); - break; - case 'boop': - this.speak(noty.message); - break; - case 'groupChange': - this.speak(`${displayName} ${noty.message}`); - break; - case 'group.announcement': - this.speak(noty.message); - break; - case 'group.informative': - this.speak(noty.message); - break; - case 'group.invite': - this.speak(noty.message); - break; - case 'group.joinRequest': - this.speak(noty.message); - break; - case 'group.transfer': - this.speak(noty.message); - break; - case 'group.queueReady': - this.speak(noty.message); - break; - case 'instance.closed': - this.speak(noty.message); - break; - case 'PortalSpawn': - if (displayName) { - this.speak( - `${displayName} has spawned a portal to ${displayLocation( - noty.instanceId, - noty.worldName, - noty.groupName - )}` - ); - } else { - this.speak('User has spawned a portal'); - } - break; - case 'AvatarChange': - this.speak( - `${displayName} changed into avatar ${noty.name}` - ); - break; - case 'ChatBoxMessage': - this.speak(`${displayName} said ${noty.text}`); - break; - case 'Event': - this.speak(noty.data); - break; - case 'External': - this.speak(noty.message); - break; - case 'VideoPlay': - this.speak(`Now playing: ${noty.notyName}`); - break; - case 'BlockedOnPlayerJoined': - this.speak(`Blocked user ${displayName} has joined`); - break; - case 'BlockedOnPlayerLeft': - this.speak(`Blocked user ${displayName} has left`); - break; - case 'MutedOnPlayerJoined': - this.speak(`Muted user ${displayName} has joined`); - break; - case 'MutedOnPlayerLeft': - this.speak(`Muted user ${displayName} has left`); - break; - case 'Blocked': - this.speak(`${displayName} has blocked you`); - break; - case 'Unblocked': - this.speak(`${displayName} has unblocked you`); - break; - case 'Muted': - this.speak(`${displayName} has muted you`); - break; - case 'Unmuted': - this.speak(`${displayName} has unmuted you`); - break; - } - }, - - displayXSNotification(noty, message, image) { - const timeout = Math.floor( - parseInt(this.notificationTimeout, 10) / 1000 - ); - const opacity = parseFloat(this.notificationOpacity) / 100; - switch (noty.type) { - case 'OnPlayerJoined': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} has joined`, - timeout, - opacity, - image - ); - break; - case 'OnPlayerLeft': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} has left`, - timeout, - opacity, - image - ); - break; - case 'OnPlayerJoining': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} is joining`, - timeout, - opacity, - image - ); - break; - case 'GPS': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} is in ${displayLocation( - noty.location, - noty.worldName, - noty.groupName - )}`, - timeout, - opacity, - image - ); - break; - case 'Online': - var locationName = ''; - if (noty.worldName) { - locationName = ` to ${displayLocation( - noty.location, - noty.worldName, - noty.groupName - )}`; - } - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} has logged in${locationName}`, - timeout, - opacity, - image - ); - break; - case 'Offline': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} has logged out`, - timeout, - opacity, - image - ); - break; - case 'Status': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} status is now ${noty.status} ${noty.statusDescription}`, - timeout, - opacity, - image - ); - break; - case 'invite': - AppApi.XSNotification( - 'VRCX', - `${ - noty.senderUsername - } has invited you to ${displayLocation( - noty.details.worldId, - noty.details.worldName - )}${message}`, - timeout, - opacity, - image - ); - break; - case 'requestInvite': - AppApi.XSNotification( - 'VRCX', - `${noty.senderUsername} has requested an invite${message}`, - timeout, - opacity, - image - ); - break; - case 'inviteResponse': - AppApi.XSNotification( - 'VRCX', - `${noty.senderUsername} has responded to your invite${message}`, - timeout, - opacity, - image - ); - break; - case 'requestInviteResponse': - AppApi.XSNotification( - 'VRCX', - `${noty.senderUsername} has responded to your invite request${message}`, - timeout, - opacity, - image - ); - break; - case 'friendRequest': - AppApi.XSNotification( - 'VRCX', - `${noty.senderUsername} has sent you a friend request`, - timeout, - opacity, - image - ); - break; - case 'Friend': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} is now your friend`, - timeout, - opacity, - image - ); - break; - case 'Unfriend': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} is no longer your friend`, - timeout, - opacity, - image - ); - break; - case 'TrustLevel': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} trust level is now ${noty.trustLevel}`, - timeout, - opacity, - image - ); - break; - case 'DisplayName': - AppApi.XSNotification( - 'VRCX', - `${noty.previousDisplayName} changed their name to ${noty.displayName}`, - timeout, - opacity, - image - ); - break; - case 'boop': - AppApi.XSNotification( - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'groupChange': - AppApi.XSNotification( - 'VRCX', - `${noty.senderUsername}: ${noty.message}`, - timeout, - opacity, - image - ); - break; - case 'group.announcement': - AppApi.XSNotification( - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'group.informative': - AppApi.XSNotification( - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'group.invite': - AppApi.XSNotification( - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'group.joinRequest': - AppApi.XSNotification( - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'group.transfer': - AppApi.XSNotification( - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'group.queueReady': - AppApi.XSNotification( - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'instance.closed': - AppApi.XSNotification( - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'PortalSpawn': - if (noty.displayName) { - AppApi.XSNotification( - 'VRCX', - `${ - noty.displayName - } has spawned a portal to ${displayLocation( - noty.instanceId, - noty.worldName, - noty.groupName - )}`, - timeout, - opacity, - image - ); - } else { - AppApi.XSNotification( - 'VRCX', - 'User has spawned a portal', - timeout, - opacity, - image - ); - } - break; - case 'AvatarChange': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} changed into avatar ${noty.name}`, - timeout, - opacity, - image - ); - break; - case 'ChatBoxMessage': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} said ${noty.text}`, - timeout, - opacity, - image - ); - break; - case 'Event': - AppApi.XSNotification( - 'VRCX', - noty.data, - timeout, - opacity, - image - ); - break; - case 'External': - AppApi.XSNotification( - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'VideoPlay': - AppApi.XSNotification( - 'VRCX', - `Now playing: ${noty.notyName}`, - timeout, - opacity, - image - ); - break; - case 'BlockedOnPlayerJoined': - AppApi.XSNotification( - 'VRCX', - `Blocked user ${noty.displayName} has joined`, - timeout, - opacity, - image - ); - break; - case 'BlockedOnPlayerLeft': - AppApi.XSNotification( - 'VRCX', - `Blocked user ${noty.displayName} has left`, - timeout, - opacity, - image - ); - break; - case 'MutedOnPlayerJoined': - AppApi.XSNotification( - 'VRCX', - `Muted user ${noty.displayName} has joined`, - timeout, - opacity, - image - ); - break; - case 'MutedOnPlayerLeft': - AppApi.XSNotification( - 'VRCX', - `Muted user ${noty.displayName} has left`, - timeout, - opacity, - image - ); - break; - case 'Blocked': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} has blocked you`, - timeout, - opacity, - image - ); - break; - case 'Unblocked': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} has unblocked you`, - timeout, - opacity, - image - ); - break; - case 'Muted': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} has muted you`, - timeout, - opacity, - image - ); - break; - case 'Unmuted': - AppApi.XSNotification( - 'VRCX', - `${noty.displayName} has unmuted you`, - timeout, - opacity, - image - ); - break; - } - }, - - displayOvrtNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - noty, - message, - image - ) { - const timeout = Math.floor( - parseInt(this.notificationTimeout, 10) / 1000 - ); - const opacity = parseFloat(this.notificationOpacity) / 100; - switch (noty.type) { - case 'OnPlayerJoined': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} has joined`, - timeout, - opacity, - image - ); - break; - case 'OnPlayerLeft': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} has left`, - timeout, - opacity, - image - ); - break; - case 'OnPlayerJoining': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} is joining`, - timeout, - opacity, - image - ); - break; - case 'GPS': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} is in ${displayLocation( - noty.location, - noty.worldName, - noty.groupName - )}`, - timeout, - opacity, - image - ); - break; - case 'Online': - var locationName = ''; - if (noty.worldName) { - locationName = ` to ${displayLocation( - noty.location, - noty.worldName, - noty.groupName - )}`; - } - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} has logged in${locationName}`, - timeout, - opacity, - image - ); - break; - case 'Offline': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} has logged out`, - timeout, - opacity, - image - ); - break; - case 'Status': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} status is now ${noty.status} ${noty.statusDescription}`, - timeout, - opacity, - image - ); - break; - case 'invite': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${ - noty.senderUsername - } has invited you to ${displayLocation( - noty.details.worldId, - noty.details.worldName - )}${message}`, - timeout, - opacity, - image - ); - break; - case 'requestInvite': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.senderUsername} has requested an invite${message}`, - timeout, - opacity, - image - ); - break; - case 'inviteResponse': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.senderUsername} has responded to your invite${message}`, - timeout, - opacity, - image - ); - break; - case 'requestInviteResponse': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.senderUsername} has responded to your invite request${message}`, - timeout, - opacity, - image - ); - break; - case 'friendRequest': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.senderUsername} has sent you a friend request`, - timeout, - opacity, - image - ); - break; - case 'Friend': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} is now your friend`, - timeout, - opacity, - image - ); - break; - case 'Unfriend': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} is no longer your friend`, - timeout, - opacity, - image - ); - break; - case 'TrustLevel': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} trust level is now ${noty.trustLevel}`, - timeout, - opacity, - image - ); - break; - case 'DisplayName': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.previousDisplayName} changed their name to ${noty.displayName}`, - timeout, - opacity, - image - ); - break; - case 'boop': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'groupChange': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.senderUsername}: ${noty.message}`, - timeout, - opacity, - image - ); - break; - case 'group.announcement': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'group.informative': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'group.invite': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'group.joinRequest': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'group.transfer': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'group.queueReady': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'instance.closed': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'PortalSpawn': - if (noty.displayName) { - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${ - noty.displayName - } has spawned a portal to ${displayLocation( - noty.instanceId, - noty.worldName, - noty.groupName - )}`, - timeout, - opacity, - image - ); - } else { - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - 'User has spawned a portal', - timeout, - opacity, - image - ); - } - break; - case 'AvatarChange': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} changed into avatar ${noty.name}`, - timeout, - opacity, - image - ); - break; - case 'ChatBoxMessage': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} said ${noty.text}`, - timeout, - opacity, - image - ); - break; - case 'Event': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - noty.data, - timeout, - opacity, - image - ); - break; - case 'External': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - noty.message, - timeout, - opacity, - image - ); - break; - case 'VideoPlay': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `Now playing: ${noty.notyName}`, - timeout, - opacity, - image - ); - break; - case 'BlockedOnPlayerJoined': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `Blocked user ${noty.displayName} has joined`, - timeout, - opacity, - image - ); - break; - case 'BlockedOnPlayerLeft': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `Blocked user ${noty.displayName} has left`, - timeout, - opacity, - image - ); - break; - case 'MutedOnPlayerJoined': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `Muted user ${noty.displayName} has joined`, - timeout, - opacity, - image - ); - break; - case 'MutedOnPlayerLeft': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `Muted user ${noty.displayName} has left`, - timeout, - opacity, - image - ); - break; - case 'Blocked': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} has blocked you`, - timeout, - opacity, - image - ); - break; - case 'Unblocked': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} has unblocked you`, - timeout, - opacity, - image - ); - break; - case 'Muted': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} has muted you`, - timeout, - opacity, - image - ); - break; - case 'Unmuted': - AppApi.OVRTNotification( - playOvrtHudNotifications, - playOvrtWristNotifications, - 'VRCX', - `${noty.displayName} has unmuted you`, - timeout, - opacity, - image - ); - break; - } - }, - - desktopNotification(displayName, message, image) { - if (WINDOWS) { - AppApi.DesktopNotification(displayName, message, image); - } else { - window.electron.desktopNotification( - displayName, - message, - image - ); - } - }, - - displayDesktopToast(noty, message, image) { - switch (noty.type) { - case 'OnPlayerJoined': - this.desktopNotification( - noty.displayName, - 'has joined', - image - ); - break; - case 'OnPlayerLeft': - this.desktopNotification( - noty.displayName, - 'has left', - image - ); - break; - case 'OnPlayerJoining': - this.desktopNotification( - noty.displayName, - 'is joining', - image - ); - break; - case 'GPS': - this.desktopNotification( - noty.displayName, - `is in ${displayLocation( - noty.location, - noty.worldName, - noty.groupName - )}`, - image - ); - break; - case 'Online': - var locationName = ''; - if (noty.worldName) { - locationName = ` to ${displayLocation( - noty.location, - noty.worldName, - noty.groupName - )}`; - } - this.desktopNotification( - noty.displayName, - `has logged in${locationName}`, - image - ); - break; - case 'Offline': - this.desktopNotification( - noty.displayName, - 'has logged out', - image - ); - break; - case 'Status': - this.desktopNotification( - noty.displayName, - `status is now ${noty.status} ${noty.statusDescription}`, - image - ); - break; - case 'invite': - this.desktopNotification( - noty.senderUsername, - `has invited you to ${displayLocation( - noty.details.worldId, - noty.details.worldName - )}${message}`, - image - ); - break; - case 'requestInvite': - this.desktopNotification( - noty.senderUsername, - `has requested an invite${message}`, - image - ); - break; - case 'inviteResponse': - this.desktopNotification( - noty.senderUsername, - `has responded to your invite${message}`, - image - ); - break; - case 'requestInviteResponse': - this.desktopNotification( - noty.senderUsername, - `has responded to your invite request${message}`, - image - ); - break; - case 'friendRequest': - this.desktopNotification( - noty.senderUsername, - 'has sent you a friend request', - image - ); - break; - case 'Friend': - this.desktopNotification( - noty.displayName, - 'is now your friend', - image - ); - break; - case 'Unfriend': - this.desktopNotification( - noty.displayName, - 'is no longer your friend', - image - ); - break; - case 'TrustLevel': - this.desktopNotification( - noty.displayName, - `trust level is now ${noty.trustLevel}`, - image - ); - break; - case 'DisplayName': - this.desktopNotification( - noty.previousDisplayName, - `changed their name to ${noty.displayName}`, - image - ); - break; - case 'boop': - this.desktopNotification( - noty.senderUsername, - noty.message, - image - ); - break; - case 'groupChange': - this.desktopNotification( - noty.senderUsername, - noty.message, - image - ); - break; - case 'group.announcement': - this.desktopNotification( - 'Group Announcement', - noty.message, - image - ); - break; - case 'group.informative': - this.desktopNotification( - 'Group Informative', - noty.message, - image - ); - break; - case 'group.invite': - this.desktopNotification( - 'Group Invite', - noty.message, - image - ); - break; - case 'group.joinRequest': - this.desktopNotification( - 'Group Join Request', - noty.message, - image - ); - break; - case 'group.transfer': - this.desktopNotification( - 'Group Transfer Request', - noty.message, - image - ); - break; - case 'group.queueReady': - this.desktopNotification( - 'Instance Queue Ready', - noty.message, - image - ); - break; - case 'instance.closed': - this.desktopNotification( - 'Instance Closed', - noty.message, - image - ); - break; - case 'PortalSpawn': - if (noty.displayName) { - this.desktopNotification( - noty.displayName, - `has spawned a portal to ${displayLocation( - noty.instanceId, - noty.worldName, - noty.groupName - )}`, - image - ); - } else { - this.desktopNotification( - '', - 'User has spawned a portal', - image - ); - } - break; - case 'AvatarChange': - this.desktopNotification( - noty.displayName, - `changed into avatar ${noty.name}`, - image - ); - break; - case 'ChatBoxMessage': - this.desktopNotification( - noty.displayName, - `said ${noty.text}`, - image - ); - break; - case 'Event': - this.desktopNotification('Event', noty.data, image); - break; - case 'External': - this.desktopNotification('External', noty.message, image); - break; - case 'VideoPlay': - this.desktopNotification( - 'Now playing', - noty.notyName, - image - ); - break; - case 'BlockedOnPlayerJoined': - this.desktopNotification( - noty.displayName, - 'blocked user has joined', - image - ); - break; - case 'BlockedOnPlayerLeft': - this.desktopNotification( - noty.displayName, - 'blocked user has left', - image - ); - break; - case 'MutedOnPlayerJoined': - this.desktopNotification( - noty.displayName, - 'muted user has joined', - image - ); - break; - case 'MutedOnPlayerLeft': - this.desktopNotification( - noty.displayName, - 'muted user has left', - image - ); - break; - case 'Blocked': - this.desktopNotification( - noty.displayName, - 'has blocked you', - image - ); - break; - case 'Unblocked': - this.desktopNotification( - noty.displayName, - 'has unblocked you', - image - ); - break; - case 'Muted': - this.desktopNotification( - noty.displayName, - 'has muted you', - image - ); - break; - case 'Unmuted': - this.desktopNotification( - noty.displayName, - 'has unmuted you', - image - ); - break; - } - } - }; -} diff --git a/src/classes/vrcxUpdater.js b/src/classes/vrcxUpdater.js deleted file mode 100644 index 889928a9..00000000 --- a/src/classes/vrcxUpdater.js +++ /dev/null @@ -1,351 +0,0 @@ -import { baseClass, $app, API, $t, $utils } from './baseClass.js'; -import * as workerTimers from 'worker-timers'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - _data = { - VRCXUpdateDialog: { - visible: false, - updatePending: false, - updatePendingIsLatest: false, - release: '', - releases: [], - json: {} - }, - branch: 'Stable', - autoUpdateVRCX: 'Auto Download', - checkingForVRCXUpdate: false, - pendingVRCXInstall: '', - pendingVRCXUpdate: false, - branches: { - Stable: { - name: 'Stable', - urlReleases: 'https://api0.vrcx.app/releases/stable', - urlLatest: 'https://api0.vrcx.app/releases/stable/latest' - }, - Nightly: { - name: 'Nightly', - urlReleases: 'https://api0.vrcx.app/releases/nightly', - urlLatest: 'https://api0.vrcx.app/releases/nightly/latest' - } - // LinuxTest: { - // name: 'LinuxTest', - // urlReleases: 'https://api.github.com/repos/rs189/VRCX/releases', - // urlLatest: - // 'https://api.github.com/repos/rs189/VRCX/releases/latest' - // } - }, - updateProgress: 0, - updateInProgress: false - }; - - _methods = { - async showVRCXUpdateDialog() { - var D = this.VRCXUpdateDialog; - D.visible = true; - D.updatePendingIsLatest = false; - D.updatePending = await AppApi.CheckForUpdateExe(); - this.loadBranchVersions(); - }, - - async downloadVRCXUpdate( - downloadUrl, - downloadName, - hashUrl, - size, - releaseName, - type - ) { - if (this.updateInProgress) { - return; - } - try { - this.updateInProgress = true; - this.downloadFileProgress(); - await AppApi.DownloadUpdate( - downloadUrl, - downloadName, - hashUrl, - size - ); - this.pendingVRCXInstall = releaseName; - } catch (err) { - console.error(err); - this.$message({ - message: `${$t('message.vrcx_updater.failed_install')} ${err}`, - type: 'error' - }); - } finally { - this.updateInProgress = false; - this.updateProgress = 0; - } - }, - - async cancelUpdate() { - await AppApi.CancelUpdate(); - this.updateInProgress = false; - this.updateProgress = 0; - }, - - async downloadFileProgress() { - this.updateProgress = await AppApi.CheckUpdateProgress(); - if (this.updateInProgress) { - workerTimers.setTimeout(() => this.downloadFileProgress(), 150); - } - }, - - updateProgressText() { - if (this.updateProgress === 100) { - return $t('message.vrcx_updater.checking_hash'); - } - return `${this.updateProgress}%`; - }, - - installVRCXUpdate() { - for (var release of this.VRCXUpdateDialog.releases) { - if (release.name !== this.VRCXUpdateDialog.release) { - continue; - } - var downloadUrl = ''; - var downloadName = ''; - var hashUrl = ''; - var size = 0; - for (var asset of release.assets) { - if (asset.state !== 'uploaded') { - continue; - } - if ( - WINDOWS && - (asset.content_type === 'application/x-msdownload' || - asset.content_type === - 'application/x-msdos-program') - ) { - downloadUrl = asset.browser_download_url; - downloadName = asset.name; - size = asset.size; - continue; - } - if ( - LINUX && - asset.content_type === 'application/octet-stream' - ) { - downloadUrl = asset.browser_download_url; - downloadName = asset.name; - size = asset.size; - continue; - } - if ( - asset.name === 'SHA256SUMS.txt' && - asset.content_type === 'text/plain' - ) { - hashUrl = asset.browser_download_url; - continue; - } - } - if (!downloadUrl) { - return; - } - var releaseName = release.name; - var type = 'Manual'; - this.downloadVRCXUpdate( - downloadUrl, - downloadName, - hashUrl, - size, - releaseName, - type - ); - break; - } - }, - - async loadBranchVersions() { - var D = this.VRCXUpdateDialog; - var url = this.branches[this.branch].urlReleases; - this.checkingForVRCXUpdate = true; - try { - var response = await webApiService.execute({ - url, - method: 'GET', - headers: { - 'VRCX-ID': this.vrcxId - } - }); - } finally { - this.checkingForVRCXUpdate = false; - } - var json = JSON.parse(response.data); - if (this.debugWebRequests) { - console.log(json, response); - } - var releases = []; - if (typeof json !== 'object' || json.message) { - $app.$message({ - message: $t('message.vrcx_updater.failed', { - message: json.message - }), - type: 'error' - }); - return; - } - for (var release of json) { - for (var asset of release.assets) { - if ( - (asset.content_type === 'application/x-msdownload' || - asset.content_type === - 'application/x-msdos-program') && - asset.state === 'uploaded' - ) { - releases.push(release); - } - } - } - D.releases = releases; - D.release = json[0].name; - this.VRCXUpdateDialog.updatePendingIsLatest = false; - if (D.release === this.pendingVRCXInstall) { - // update already downloaded and latest version - this.VRCXUpdateDialog.updatePendingIsLatest = true; - } - if ( - (await configRepository.getString('VRCX_branch')) !== - this.branch - ) { - await configRepository.setString('VRCX_branch', this.branch); - } - }, - - async checkForVRCXUpdate() { - var currentVersion = this.appVersion.replace(' (Linux)', ''); - if ( - !currentVersion || - currentVersion === 'VRCX Nightly Build' || - currentVersion === 'VRCX Build' - ) { - // ignore custom builds - return; - } - if (this.branch === 'Beta') { - // move Beta users to stable - this.branch = 'Stable'; - await configRepository.setString('VRCX_branch', this.branch); - } - if (typeof this.branches[this.branch] === 'undefined') { - // handle invalid branch - this.branch = 'Stable'; - await configRepository.setString('VRCX_branch', this.branch); - } - var url = this.branches[this.branch].urlLatest; - this.checkingForVRCXUpdate = true; - try { - var response = await webApiService.execute({ - url, - method: 'GET', - headers: { - 'VRCX-ID': this.vrcxId - } - }); - } finally { - this.checkingForVRCXUpdate = false; - } - this.pendingVRCXUpdate = false; - var json = JSON.parse(response.data); - if (this.debugWebRequests) { - console.log(json, response); - } - if (json === Object(json) && json.name && json.published_at) { - this.VRCXUpdateDialog.updateJson = json; - this.changeLogDialog.buildName = json.name; - this.changeLogDialog.changeLog = this.changeLogRemoveLinks( - json.body - ); - var releaseName = json.name; - this.latestAppVersion = releaseName; - this.VRCXUpdateDialog.updatePendingIsLatest = false; - if (releaseName === this.pendingVRCXInstall) { - // update already downloaded - this.VRCXUpdateDialog.updatePendingIsLatest = true; - } else if (releaseName > currentVersion) { - var downloadUrl = ''; - var downloadName = ''; - var hashUrl = ''; - var size = 0; - for (var asset of json.assets) { - if (asset.state !== 'uploaded') { - continue; - } - if ( - !LINUX && - (asset.content_type === - 'application/x-msdownload' || - asset.content_type === - 'application/x-msdos-program') - ) { - downloadUrl = asset.browser_download_url; - downloadName = asset.name; - size = asset.size; - continue; - } - if ( - LINUX && - asset.content_type === 'application/octet-stream' - ) { - downloadUrl = asset.browser_download_url; - downloadName = asset.name; - size = asset.size; - continue; - } - if ( - asset.name === 'SHA256SUMS.txt' && - asset.content_type === 'text/plain' - ) { - hashUrl = asset.browser_download_url; - continue; - } - } - if (!downloadUrl) { - return; - } - this.pendingVRCXUpdate = true; - this.notifyMenu('settings'); - var type = 'Auto'; - if (!API.isLoggedIn) { - this.showVRCXUpdateDialog(); - } else if (this.autoUpdateVRCX === 'Notify') { - // this.showVRCXUpdateDialog(); - } else if (this.autoUpdateVRCX === 'Auto Download') { - this.downloadVRCXUpdate( - downloadUrl, - downloadName, - hashUrl, - size, - releaseName, - type - ); - } - } - } - }, - - restartVRCX(isUpgrade) { - if (!LINUX) { - AppApi.RestartApplication(isUpgrade); - } else { - window.electron.restartApp(); - } - }, - - async saveAutoUpdateVRCX() { - if (this.autoUpdateVRCX === 'Off') { - this.pendingVRCXUpdate = false; - } - await configRepository.setString( - 'VRCX_autoUpdateVRCX', - this.autoUpdateVRCX - ); - } - }; -} diff --git a/src/classes/websocket.js b/src/classes/websocket.js deleted file mode 100644 index dad8137e..00000000 --- a/src/classes/websocket.js +++ /dev/null @@ -1,620 +0,0 @@ -import * as workerTimers from 'worker-timers'; -import Noty from 'noty'; -import { parseLocation } from '../composables/instance/utils'; -import { baseClass, $app, API, $utils } from './baseClass.js'; -import { groupRequest } from '../api'; - -export default class extends baseClass { - constructor(_app, _API, _t) { - super(_app, _API, _t); - } - - init() { - API.webSocket = null; - API.lastWebSocketMessage = ''; - - API.$on('USER:CURRENT', function () { - if ($app.friendLogInitStatus && this.webSocket === null) { - this.getAuth(); - } - }); - - API.getAuth = function () { - return this.call('auth', { - method: 'GET' - }).then((json) => { - var args = { - json - }; - this.$emit('AUTH', args); - return args; - }); - }; - - API.$on('AUTH', function (args) { - if (args.json.ok) { - this.connectWebSocket(args.json.token); - } - }); - - API.connectWebSocket = function (token) { - if (this.webSocket !== null) { - return; - } - var socket = new WebSocket(`${API.websocketDomain}/?auth=${token}`); - socket.onopen = () => { - if ($app.debugWebSocket) { - console.log('WebSocket connected'); - } - }; - socket.onclose = () => { - if (this.webSocket === socket) { - this.webSocket = null; - } - try { - socket.close(); - } catch (err) {} - if ($app.debugWebSocket) { - console.log('WebSocket closed'); - } - workerTimers.setTimeout(() => { - if ( - this.isLoggedIn && - $app.friendLogInitStatus && - this.webSocket === null - ) { - this.getAuth(); - } - }, 5000); - }; - socket.onerror = () => { - if (this.errorNoty) { - this.errorNoty.close(); - } - this.errorNoty = new Noty({ - type: 'error', - text: 'WebSocket Error' - }).show(); - socket.onclose(); - }; - socket.onmessage = ({ data }) => { - try { - if (this.lastWebSocketMessage === data) { - // pls no spam - return; - } - this.lastWebSocketMessage = data; - var json = JSON.parse(data); - try { - json.content = JSON.parse(json.content); - } catch (err) {} - this.$emit('PIPELINE', { - json - }); - if ($app.debugWebSocket && json.content) { - var displayName = ''; - var user = this.cachedUsers.get(json.content.userId); - if (user) { - displayName = user.displayName; - } - console.log( - 'WebSocket', - json.type, - displayName, - json.content - ); - } - } catch (err) { - console.error(err); - } - }; - this.webSocket = socket; - }; - - API.$on('LOGOUT', function () { - this.closeWebSocket(); - }); - - API.closeWebSocket = function () { - var socket = this.webSocket; - if (socket === null) { - return; - } - this.webSocket = null; - try { - socket.close(); - } catch (err) {} - }; - - API.reconnectWebSocket = function () { - if (!this.isLoggedIn || !$app.friendLogInitStatus) { - return; - } - this.closeWebSocket(); - this.getAuth(); - }; - - API.$on('PIPELINE', function (args) { - var { type, content, err } = args.json; - if (typeof err !== 'undefined') { - console.error('PIPELINE: error', args); - if (this.errorNoty) { - this.errorNoty.close(); - } - this.errorNoty = new Noty({ - type: 'error', - text: $app.escapeTag(`WebSocket Error: ${err}`) - }).show(); - return; - } - if (typeof content === 'undefined') { - console.error('PIPELINE: missing content', args); - return; - } - if (typeof content.user !== 'undefined') { - // I forgot about this... - delete content.user.state; - } - switch (type) { - case 'notification': - this.$emit('NOTIFICATION', { - json: content, - params: { - notificationId: content.id - } - }); - this.$emit('PIPELINE:NOTIFICATION', { - json: content, - params: { - notificationId: content.id - } - }); - break; - - case 'notification-v2': - console.log('notification-v2', content); - this.$emit('NOTIFICATION:V2', { - json: content, - params: { - notificationId: content.id - } - }); - break; - - case 'notification-v2-delete': - console.log('notification-v2-delete', content); - for (var id of content.ids) { - this.$emit('NOTIFICATION:HIDE', { - params: { - notificationId: id - } - }); - this.$emit('NOTIFICATION:SEE', { - params: { - notificationId: id - } - }); - } - break; - - case 'notification-v2-update': - console.log('notification-v2-update', content); - this.$emit('NOTIFICATION:V2:UPDATE', { - json: content.updates, - params: { - notificationId: content.id - } - }); - break; - - case 'see-notification': - this.$emit('NOTIFICATION:SEE', { - params: { - notificationId: content - } - }); - break; - - case 'hide-notification': - this.$emit('NOTIFICATION:HIDE', { - params: { - notificationId: content - } - }); - this.$emit('NOTIFICATION:SEE', { - params: { - notificationId: content - } - }); - break; - - case 'response-notification': - this.$emit('NOTIFICATION:HIDE', { - params: { - notificationId: content.notificationId - } - }); - this.$emit('NOTIFICATION:SEE', { - params: { - notificationId: content.notificationId - } - }); - break; - - case 'friend-add': - this.$emit('USER', { - json: content.user, - params: { - userId: content.userId - } - }); - this.$emit('FRIEND:ADD', { - params: { - userId: content.userId - } - }); - break; - - case 'friend-delete': - this.$emit('FRIEND:DELETE', { - params: { - userId: content.userId - } - }); - break; - - case 'friend-online': - // Where is instanceId, travelingToWorld, travelingToInstance? - // More JANK, what a mess - var $location = parseLocation(content.location); - var $travelingToLocation = parseLocation( - content.travelingToLocation - ); - if (content?.user?.id) { - this.$emit('USER', { - json: { - id: content.userId, - platform: content.platform, - state: 'online', - - location: content.location, - worldId: content.worldId, - instanceId: $location.instanceId, - travelingToLocation: - content.travelingToLocation, - travelingToWorld: $travelingToLocation.worldId, - travelingToInstance: - $travelingToLocation.instanceId, - - ...content.user - }, - params: { - userId: content.userId - } - }); - } else { - this.$emit('FRIEND:STATE', { - json: { - state: 'online' - }, - params: { - userId: content.userId - } - }); - } - break; - - case 'friend-active': - if (content?.user?.id) { - this.$emit('USER', { - json: { - id: content.userId, - platform: content.platform, - state: 'active', - - location: 'offline', - worldId: 'offline', - instanceId: 'offline', - travelingToLocation: 'offline', - travelingToWorld: 'offline', - travelingToInstance: 'offline', - - ...content.user - }, - params: { - userId: content.userId - } - }); - } else { - this.$emit('FRIEND:STATE', { - json: { - state: 'active' - }, - params: { - userId: content.userId - } - }); - } - break; - - case 'friend-offline': - // more JANK, hell yeah - this.$emit('USER', { - json: { - id: content.userId, - platform: content.platform, - state: 'offline', - - location: 'offline', - worldId: 'offline', - instanceId: 'offline', - travelingToLocation: 'offline', - travelingToWorld: 'offline', - travelingToInstance: 'offline' - }, - params: { - userId: content.userId - } - }); - break; - - case 'friend-update': - this.$emit('USER', { - json: content.user, - params: { - userId: content.userId - } - }); - break; - - case 'friend-location': - var $location = parseLocation(content.location); - var $travelingToLocation = parseLocation( - content.travelingToLocation - ); - if (!content?.user?.id) { - var ref = this.cachedUsers.get(content.userId); - if (typeof ref !== 'undefined') { - this.$emit('USER', { - json: { - ...ref, - location: content.location, - worldId: content.worldId, - instanceId: $location.instanceId, - travelingToLocation: - content.travelingToLocation, - travelingToWorld: - $travelingToLocation.worldId, - travelingToInstance: - $travelingToLocation.instanceId - }, - params: { - userId: content.userId - } - }); - } - break; - } - this.$emit('USER', { - json: { - location: content.location, - worldId: content.worldId, - instanceId: $location.instanceId, - travelingToLocation: content.travelingToLocation, - travelingToWorld: $travelingToLocation.worldId, - travelingToInstance: - $travelingToLocation.instanceId, - ...content.user, - state: 'online' // JANK - }, - params: { - userId: content.userId - } - }); - break; - - case 'user-update': - this.$emit('USER:CURRENT', { - json: content.user, - params: { - userId: content.userId - } - }); - break; - - case 'user-location': - // update current user location - if (content.userId !== this.currentUser.id) { - console.error('user-location wrong userId', content); - break; - } - - // content.user: {} // we don't trust this - // content.world: {} // this is long gone - // content.worldId // where did worldId go? - // content.instance // without worldId, this is useless - - $app.setCurrentUserLocation( - content.location, - content.travelingToLocation - ); - break; - - case 'group-joined': - // var groupId = content.groupId; - // $app.onGroupJoined(groupId); - break; - - case 'group-left': - // var groupId = content.groupId; - // $app.onGroupLeft(groupId); - break; - - case 'group-role-updated': - var groupId = content.role.groupId; - groupRequest.getGroup({ groupId, includeRoles: true }); - console.log('group-role-updated', content); - - // content { - // role: { - // createdAt: string, - // description: string, - // groupId: string, - // id: string, - // isManagementRole: boolean, - // isSelfAssignable: boolean, - // name: string, - // order: number, - // permissions: string[], - // requiresPurchase: boolean, - // requiresTwoFactor: boolean - break; - - case 'group-member-updated': - var member = content.member; - if (!member) { - console.error( - 'group-member-updated missing member', - content - ); - break; - } - var groupId = member.groupId; - if ( - $app.groupDialog.visible && - $app.groupDialog.id === groupId - ) { - $app.getGroupDialogGroup(groupId); - } - this.$emit('GROUP:MEMBER', { - json: member, - params: { - groupId - } - }); - console.log('group-member-updated', member); - break; - - case 'instance-queue-joined': - case 'instance-queue-position': - var instanceId = content.instanceLocation; - var position = content.position ?? 0; - var queueSize = content.queueSize ?? 0; - $app.instanceQueueUpdate(instanceId, position, queueSize); - break; - - case 'instance-queue-ready': - var instanceId = content.instanceLocation; - // var expiry = Date.parse(content.expiry); - $app.instanceQueueReady(instanceId); - break; - - case 'instance-queue-left': - var instanceId = content.instanceLocation; - $app.removeQueuedInstance(instanceId); - // $app.instanceQueueClear(); - break; - - case 'content-refresh': - var contentType = content.contentType; - console.log('content-refresh', content); - if (contentType === 'icon') { - if ( - $app.galleryDialogVisible && - !$app.galleryDialogIconsLoading - ) { - $app.refreshVRCPlusIconsTable(); - } - } else if (contentType === 'gallery') { - if ( - $app.galleryDialogVisible && - !$app.galleryDialogGalleryLoading - ) { - $app.refreshGalleryTable(); - } - } else if (contentType === 'emoji') { - if ( - $app.galleryDialogVisible && - !$app.galleryDialogEmojisLoading - ) { - $app.refreshEmojiTable(); - } - } else if (contentType === 'sticker') { - // on sticker upload - } else if (contentType === 'print') { - if ( - $app.autoDeleteOldPrints && - content.actionType === 'created' - ) { - $app.tryDeleteOldPrints(); - } else if ( - $app.galleryDialogVisible && - !$app.galleryDialogPrintsLoading - ) { - $app.refreshPrintTable(); - } - } else if (contentType === 'prints') { - // lol - } else if (contentType === 'avatar') { - // hmm, utilizing this might be too spamy and cause UI to move around - } else if (contentType === 'world') { - // hmm - } else if (contentType === 'created') { - // on avatar upload, might be gone now - } else if (contentType === 'avatargallery') { - // on avatar gallery image upload - } else if (contentType === 'invitePhoto') { - // on uploading invite photo - } else if (contentType === 'inventory') { - if ( - $app.galleryDialogVisible && - !$app.galleryDialogInventoryLoading - ) { - $app.getInventory(); - } - // on consuming a bundle - // {contentType: 'inventory', itemId: 'inv_', itemType: 'prop', actionType: 'add'} - } else if (!contentType) { - console.log( - 'content-refresh without contentType', - content - ); - } else { - console.log( - 'Unknown content-refresh type', - content.contentType - ); - } - break; - - case 'instance-closed': - // TODO: get worldName, groupName, hardClose - var noty = { - type: 'instance.closed', - location: content.instanceLocation, - message: 'Instance Closed', - created_at: new Date().toJSON() - }; - if ( - $app.notificationTable.filters[0].value.length === 0 || - $app.notificationTable.filters[0].value.includes( - noty.type - ) - ) { - $app.notifyMenu('notification'); - } - $app.queueNotificationNoty(noty); - $app.notificationTable.data.push(noty); - $app.updateSharedFeed(true); - break; - - default: - console.log('Unknown pipeline type', args.json); - } - }); - } - - _data = {}; - - _methods = {}; -} diff --git a/src/components/AvatarInfo.vue b/src/components/AvatarInfo.vue new file mode 100644 index 00000000..24ef9bd8 --- /dev/null +++ b/src/components/AvatarInfo.vue @@ -0,0 +1,73 @@ + + + diff --git a/src/components/CountdownTimer.vue b/src/components/CountdownTimer.vue new file mode 100644 index 00000000..79860336 --- /dev/null +++ b/src/components/CountdownTimer.vue @@ -0,0 +1,33 @@ + + + diff --git a/src/components/DisplayName.vue b/src/components/DisplayName.vue new file mode 100644 index 00000000..a353c5a7 --- /dev/null +++ b/src/components/DisplayName.vue @@ -0,0 +1,41 @@ + + + diff --git a/src/components/FriendItem.vue b/src/components/FriendItem.vue index 838e5bee..07779043 100644 --- a/src/components/FriendItem.vue +++ b/src/components/FriendItem.vue @@ -21,14 +21,12 @@ - - diff --git a/src/components/dialogs/LaunchDialog.vue b/src/components/dialogs/LaunchDialog.vue index feca0ab4..94baad39 100644 --- a/src/components/dialogs/LaunchDialog.vue +++ b/src/components/dialogs/LaunchDialog.vue @@ -1,13 +1,13 @@ - diff --git a/src/components/dialogs/NewInstanceDialog.vue b/src/components/dialogs/NewInstanceDialog.vue index 20e98e74..bea3c497 100644 --- a/src/components/dialogs/NewInstanceDialog.vue +++ b/src/components/dialogs/NewInstanceDialog.vue @@ -1,52 +1,52 @@ - diff --git a/src/components/dialogs/PreviousImagesDialog.vue b/src/components/dialogs/PreviousImagesDialog.vue index 4756650c..3816a250 100644 --- a/src/components/dialogs/PreviousImagesDialog.vue +++ b/src/components/dialogs/PreviousImagesDialog.vue @@ -26,26 +26,16 @@ diff --git a/src/components/dialogs/PreviousInstancesDialog/PreviousInstancesInfoDialog.vue b/src/components/dialogs/PreviousInstancesDialog/PreviousInstancesInfoDialog.vue index 77379c17..0a7b5427 100644 --- a/src/components/dialogs/PreviousInstancesDialog/PreviousInstancesInfoDialog.vue +++ b/src/components/dialogs/PreviousInstancesDialog/PreviousInstancesInfoDialog.vue @@ -1,14 +1,14 @@ @@ -57,105 +57,85 @@ - diff --git a/src/components/dialogs/PreviousInstancesDialog/PreviousInstancesWorldDialog.vue b/src/components/dialogs/PreviousInstancesDialog/PreviousInstancesWorldDialog.vue index 35c45cf1..0ec2cd4e 100644 --- a/src/components/dialogs/PreviousInstancesDialog/PreviousInstancesWorldDialog.vue +++ b/src/components/dialogs/PreviousInstancesDialog/PreviousInstancesWorldDialog.vue @@ -2,45 +2,44 @@
- + - + - + - + - + - diff --git a/src/components/dialogs/UserDialog/BioDialog.vue b/src/components/dialogs/UserDialog/BioDialog.vue index f9aa99a1..20fc0e74 100644 --- a/src/components/dialogs/UserDialog/BioDialog.vue +++ b/src/components/dialogs/UserDialog/BioDialog.vue @@ -20,7 +20,6 @@ @@ -52,7 +51,7 @@ import { getCurrentInstance } from 'vue'; import { useI18n } from 'vue-i18n-bridge'; import { userRequest } from '../../../api'; - import { getFaviconUrl } from '../../../composables/shared/utils'; + import { getFaviconUrl } from '../../../shared/utils'; const { t } = useI18n(); const { $message } = getCurrentInstance().proxy; diff --git a/src/components/dialogs/UserDialog/LanguageDialog.vue b/src/components/dialogs/UserDialog/LanguageDialog.vue index 3a9ece90..6c8881e4 100644 --- a/src/components/dialogs/UserDialog/LanguageDialog.vue +++ b/src/components/dialogs/UserDialog/LanguageDialog.vue @@ -6,7 +6,7 @@ width="400px" append-to-body>
-
+
@@ -46,29 +44,21 @@ diff --git a/src/components/dialogs/UserDialog/SendInviteRequestDialog.vue b/src/components/dialogs/UserDialog/SendInviteRequestDialog.vue index 4d3f9231..a5cc1484 100644 --- a/src/components/dialogs/UserDialog/SendInviteRequestDialog.vue +++ b/src/components/dialogs/UserDialog/SendInviteRequestDialog.vue @@ -6,7 +6,7 @@ width="800px" append-to-body @close="cancelSendInviteRequest"> - @@ -53,37 +53,37 @@ :visible.sync="isSendInviteConfirmDialogVisible" :send-invite-dialog="sendInviteDialog" :invite-dialog="inviteDialog" - :upload-image="uploadImage" @closeInviteDialog="closeInviteDialog" /> diff --git a/src/components/dialogs/WorldDialog/ChangeWorldImageDialog.vue b/src/components/dialogs/WorldDialog/ChangeWorldImageDialog.vue index 1b3896dc..08ac6518 100644 --- a/src/components/dialogs/WorldDialog/ChangeWorldImageDialog.vue +++ b/src/components/dialogs/WorldDialog/ChangeWorldImageDialog.vue @@ -25,12 +25,9 @@
-
+
diff --git a/src/components/dialogs/WorldDialog/SetWorldTagsDialog.vue b/src/components/dialogs/WorldDialog/SetWorldTagsDialog.vue index 7633d56f..ea1b7947 100644 --- a/src/components/dialogs/WorldDialog/SetWorldTagsDialog.vue +++ b/src/components/dialogs/WorldDialog/SetWorldTagsDialog.vue @@ -1,22 +1,22 @@ - diff --git a/src/components/dialogs/WorldDialog/WorldAllowedDomainsDialog.vue b/src/components/dialogs/WorldDialog/WorldAllowedDomainsDialog.vue index 7db42134..1598f4c3 100644 --- a/src/components/dialogs/WorldDialog/WorldAllowedDomainsDialog.vue +++ b/src/components/dialogs/WorldDialog/WorldAllowedDomainsDialog.vue @@ -1,7 +1,7 @@ - diff --git a/src/components/dialogs/WorldDialog/WorldDialog.vue b/src/components/dialogs/WorldDialog/WorldDialog.vue index 7af0ff2d..80154a26 100644 --- a/src/components/dialogs/WorldDialog/WorldDialog.vue +++ b/src/components/dialogs/WorldDialog/WorldDialog.vue @@ -1,6 +1,6 @@ - diff --git a/src/views/Favorites/dialogs/AvatarExportDialog.vue b/src/views/Favorites/dialogs/AvatarExportDialog.vue index 2838f481..5dc7fad7 100644 --- a/src/views/Favorites/dialogs/AvatarExportDialog.vue +++ b/src/views/Favorites/dialogs/AvatarExportDialog.vue @@ -1,5 +1,5 @@