diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index febcc61..b55f858 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,8 +9,26 @@ permissions: contents: write jobs: + # ─── Create a single release ──────────────────────────────────────────────── + create-release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Create release + run: | + gh release create ${{ github.ref_name }} \ + --title "Modly Beta ${{ github.ref_name }}" \ + --generate-notes \ + --latest \ + --repo ${{ github.repository }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # ─── Windows build ──────────────────────────────────────────────────────────── build-windows: + needs: create-release runs-on: windows-latest steps: - name: Checkout @@ -29,18 +47,26 @@ jobs: run: node scripts/download-python-embed.js - name: Build & Package (Windows) + shell: bash run: npx electron-vite build && npx electron-builder --win --publish never env: CSC_IDENTITY_AUTO_DISCOVERY: false - - name: Upload Windows artifact - uses: actions/upload-artifact@v4 - with: - name: windows-installer - path: dist/*.exe + - name: Upload assets to release + shell: bash + run: | + gh release upload ${{ github.ref_name }} \ + dist/*.exe \ + dist/*.exe.blockmap \ + dist/latest.yml \ + --repo ${{ github.repository }} \ + --clobber + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # ─── Linux build ───────────────────────────────────────────────────────────── build-linux: + needs: create-release runs-on: ubuntu-latest steps: - name: Checkout @@ -55,42 +81,15 @@ jobs: - name: Install dependencies run: npm install - - name: Install Linux build dependencies - run: sudo apt-get install -y rpm - - name: Build & Package (Linux) run: npx electron-vite build && npx electron-builder --linux --publish never - - name: Upload Linux artifact - uses: actions/upload-artifact@v4 - with: - name: linux-installer - path: dist/*.AppImage - - # ─── Create GitHub Release ─────────────────────────────────────────────────── - release: - needs: [build-windows, build-linux] - runs-on: ubuntu-latest - steps: - - name: Download Windows artifact - uses: actions/download-artifact@v4 - with: - name: windows-installer - path: artifacts/windows - - - name: Download Linux artifact - uses: actions/download-artifact@v4 - with: - name: linux-installer - path: artifacts/linux - - - name: Create GitHub Release + - name: Upload assets to release run: | - gh release create ${{ github.ref_name }} \ - artifacts/windows/*.exe \ - artifacts/linux/*.AppImage \ - --title "Modly Beta ${{ github.ref_name }}" \ - --generate-notes \ - --repo ${{ github.repository }} + gh release upload ${{ github.ref_name }} \ + dist/*.AppImage \ + dist/latest-linux.yml \ + --repo ${{ github.repository }} \ + --clobber env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/api/main.py b/api/main.py index 7465692..c102087 100644 --- a/api/main.py +++ b/api/main.py @@ -5,7 +5,8 @@ from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -from fastapi.staticfiles import StaticFiles +from fastapi.responses import FileResponse +from fastapi import HTTPException from routers import generation, model, optimize, status, settings, extensions, export @@ -22,7 +23,7 @@ async def lifespan(app: FastAPI): app = FastAPI( title="Modly API", - version="0.1.3", + version="0.2.0", lifespan=lifespan, ) @@ -41,6 +42,11 @@ async def lifespan(app: FastAPI): app.include_router(extensions.router, prefix="/extensions") app.include_router(export.router, prefix="/export") -# Serve generated GLB files from workspace -from services.generator_registry import WORKSPACE_DIR -app.mount("/workspace", StaticFiles(directory=str(WORKSPACE_DIR)), name="workspace") +# Serve generated files from workspace — dynamic so path changes take effect immediately +@app.get("/workspace/{full_path:path}") +async def serve_workspace_file(full_path: str): + import services.generator_registry as reg + file_path = reg.WORKSPACE_DIR / full_path + if not file_path.exists() or not file_path.is_file(): + raise HTTPException(status_code=404, detail="File not found") + return FileResponse(str(file_path)) diff --git a/api/routers/generation.py b/api/routers/generation.py index 8bdde97..ea9dead 100644 --- a/api/routers/generation.py +++ b/api/routers/generation.py @@ -4,7 +4,7 @@ import uuid from typing import Dict from fastapi import APIRouter, File, Form, UploadFile, HTTPException, BackgroundTasks -from services.generators.base import smooth_progress +from services.generators.base import smooth_progress, GenerationCancelled import re as _re from services.generator_registry import generator_registry, WORKSPACE_DIR @@ -13,6 +13,8 @@ router = APIRouter(tags=["generation"]) _jobs: Dict[str, JobStatus] = {} +_cancelled: set = set() +_cancel_events: Dict[str, threading.Event] = {} @router.post("/from-image") @@ -71,6 +73,7 @@ async def generate_from_image( job = JobStatus(job_id=job_id, status="pending", progress=0) _jobs[job_id] = job + _cancel_events[job_id] = threading.Event() background_tasks.add_task(_run_generation, job_id, image_bytes, params, collection) @@ -86,6 +89,19 @@ async def job_status(job_id: str): return job +@router.post("/cancel/{job_id}") +async def cancel_job(job_id: str): + job = _jobs.get(job_id) + if not job: + raise HTTPException(404, f"Job {job_id} not found") + _cancelled.add(job_id) + if job_id in _cancel_events: + _cancel_events[job_id].set() + if job.status in ("pending", "running"): + job.status = "cancelled" + return {"cancelled": True} + + async def _run_generation(job_id: str, image_bytes: bytes, params: dict, collection: str = "Default") -> None: job = _jobs[job_id] job.status = "running" @@ -118,20 +134,36 @@ def progress_cb(pct: int, step: str = "") -> None: else: gen = await loop.run_in_executor(None, generator_registry.get_active) + if job_id in _cancelled: + return + # Direct output to the collection subfolder coll_dir = WORKSPACE_DIR / collection coll_dir.mkdir(parents=True, exist_ok=True) gen.outputs_dir = coll_dir + cancel_event = _cancel_events.get(job_id) + import inspect + supports_cancel = "cancel_event" in inspect.signature(gen.generate).parameters output_path = await loop.run_in_executor( None, - lambda: gen.generate(image_bytes, params, progress_cb), + lambda: gen.generate(image_bytes, params, progress_cb, cancel_event) + if supports_cancel + else gen.generate(image_bytes, params, progress_cb), ) + + if job_id in _cancelled: + return + job.status = "done" job.progress = 100 job.output_url = f"/workspace/{collection}/{output_path.name}" + except GenerationCancelled: + job.status = "cancelled" except Exception as exc: + if job_id in _cancelled: + return tb = traceback.format_exc() print(f"[Generation ERROR] {exc}\n{tb}") job.status = "error" diff --git a/api/routers/model.py b/api/routers/model.py index 5a4d53d..6ababd5 100644 --- a/api/routers/model.py +++ b/api/routers/model.py @@ -39,6 +39,23 @@ async def switch_model(model_id: str): raise HTTPException(400, str(e)) +@router.post("/unload-all") +async def unload_all_models(): + """Unloads all models from memory to free VRAM/RAM.""" + generator_registry.unload_all() + # Force Python to release memory back to the OS + import gc + gc.collect() + try: + import ctypes, sys + if sys.platform == "win32": + k32 = ctypes.windll.kernel32 + k32.SetProcessWorkingSetSizeEx(k32.GetCurrentProcess(), -1, -1, 0) + except Exception: + pass + return {"unloaded": True} + + @router.post("/unload/{model_id}") async def unload_model(model_id: str): """Unloads a model from memory so its files can be safely deleted.""" @@ -51,19 +68,30 @@ async def unload_model(model_id: str): @router.get("/hf-download") -async def hf_download(repo_id: str, model_id: str): +async def hf_download(repo_id: str, model_id: str, skip_prefixes: Optional[str] = None): """ Streams a HuggingFace Hub model download via SSE. Downloads into MODELS_DIR / model_id applying the filtering declared in the extension manifest (hf_skip_prefixes). + skip_prefixes: JSON-encoded list of path prefixes to exclude (passed from Electron). + Falls back to registry manifest if not provided. + SSE format: data: {"percent": 0-100, "file": "...", "status": "..."} """ + import json as _json dest_dir = str(MODELS_DIR / model_id) - try: - skip_list = generator_registry.get_manifest(model_id).get("hf_skip_prefixes", []) - except KeyError: - skip_list = [] + # Prefer skip_prefixes passed directly from the client (authoritative, no registry dep) + if skip_prefixes: + try: + skip_list = _json.loads(skip_prefixes) + except Exception: + skip_list = [] + else: + try: + skip_list = generator_registry.get_manifest(model_id).get("hf_skip_prefixes", []) + except KeyError: + skip_list = [] async def stream(): loop = asyncio.get_running_loop() @@ -105,7 +133,7 @@ def _dl(f=filename): # Reserve 1-95 for file downloads, leave 95-100 for finalisation pct = 1 + round((i + 1) / total * 94) - yield _fmt({"percent": pct, "file": filename}) + yield _fmt({"percent": pct, "file": filename, "fileIndex": i + 1, "totalFiles": total}) yield _fmt({"percent": 100, "status": "done"}) diff --git a/api/schemas/generation.py b/api/schemas/generation.py index 960318c..7ed6ca6 100644 --- a/api/schemas/generation.py +++ b/api/schemas/generation.py @@ -4,7 +4,7 @@ class JobStatus(BaseModel): job_id: str - status: Literal["pending", "running", "done", "error"] + status: Literal["pending", "running", "done", "error", "cancelled"] progress: int = 0 # 0–100 step: Optional[str] = None # Human-readable current step output_url: Optional[str] = None diff --git a/api/services/generator_registry.py b/api/services/generator_registry.py index 698d5d4..01854b1 100644 --- a/api/services/generator_registry.py +++ b/api/services/generator_registry.py @@ -327,6 +327,7 @@ def update_paths(self, models_dir: Optional[Path], workspace_dir: Optional[Path] import services.generator_registry as _self_module if models_dir is not None: + self.unload_all() models_dir.mkdir(parents=True, exist_ok=True) _self_module.MODELS_DIR = models_dir for model_id, gen in self._generators.items(): diff --git a/api/services/generators/base.py b/api/services/generators/base.py index fdcb32a..a23b01d 100644 --- a/api/services/generators/base.py +++ b/api/services/generators/base.py @@ -7,6 +7,10 @@ from typing import Callable, Optional +class GenerationCancelled(Exception): + """Raised by generators when a cancel_event is set mid-generation.""" + + def smooth_progress( progress_cb: Callable[[int, str], None], start: int, @@ -73,6 +77,25 @@ def load(self) -> None: def unload(self) -> None: """Release memory. Can be overridden if needed.""" self._model = None + import gc + gc.collect() + try: + import torch + if torch.cuda.is_available(): + torch.cuda.empty_cache() + except ImportError: + pass + # Force the OS to reclaim unused memory from this process + try: + import ctypes + import sys + if sys.platform == "win32": + kernel32 = ctypes.windll.kernel32 + kernel32.SetProcessWorkingSetSizeEx( + kernel32.GetCurrentProcess(), -1, -1, 0 + ) + except Exception: + pass def is_loaded(self) -> bool: return self._model is not None @@ -87,14 +110,21 @@ def generate( image_bytes: bytes, params: dict, progress_cb: Optional[Callable[[int, str], None]] = None, + cancel_event: Optional[threading.Event] = None, ) -> Path: """ Starts 3D generation from an image. Returns the path to the generated .glb file. progress_cb(percent: int, step_label: str) + cancel_event: set this to interrupt generation between steps. """ ... + def _check_cancelled(self, cancel_event: Optional[threading.Event]) -> None: + """Raises GenerationCancelled if cancel_event is set.""" + if cancel_event and cancel_event.is_set(): + raise GenerationCancelled() + # ------------------------------------------------------------------ # # Parameter schema (for the UI) # ------------------------------------------------------------------ # diff --git a/api/services/generators/hunyuan3d.py b/api/services/generators/hunyuan3d.py index 2a2b247..5f63570 100644 --- a/api/services/generators/hunyuan3d.py +++ b/api/services/generators/hunyuan3d.py @@ -69,15 +69,6 @@ def load(self) -> None: self._model = pipeline print(f"[Hunyuan3DGenerator] Loaded on {device}.") - def unload(self) -> None: - super().unload() - try: - import torch - if torch.cuda.is_available(): - torch.cuda.empty_cache() - except ImportError: - pass - # ------------------------------------------------------------------ # # Inference # ------------------------------------------------------------------ # diff --git a/electron/main/index.ts b/electron/main/index.ts index be04a0e..653e747 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -3,7 +3,8 @@ import { join } from 'path' import { electronApp, optimizer, is } from '@electron-toolkit/utils' import { setupIpcHandlers } from './ipc-handlers' import { PythonBridge } from './python-bridge' -import { logger } from './logger' +import { logger, archiveCurrentSession } from './logger' +import { initAutoUpdater } from './updater' let mainWindow: BrowserWindow | null = null let pythonBridge: PythonBridge | null = null @@ -48,13 +49,17 @@ app.setName('Modly') process.on('uncaughtException', (err) => { logger.error(`Uncaught exception: ${err.stack ?? err.message}`) + mainWindow?.webContents.send('app:error', err.stack ?? err.message) }) process.on('unhandledRejection', (reason) => { - logger.error(`Unhandled rejection: ${String(reason)}`) + const msg = String(reason) + logger.error(`Unhandled rejection: ${msg}`) + mainWindow?.webContents.send('app:error', msg) }) app.whenReady().then(async () => { + archiveCurrentSession() logger.info(`App started — version ${app.getVersion()}`) electronApp.setAppUserModelId('com.modly.app') @@ -69,6 +74,7 @@ app.whenReady().then(async () => { pythonBridge = new PythonBridge() pythonBridge.setWindowGetter(() => mainWindow) setupIpcHandlers(pythonBridge, () => mainWindow) + initAutoUpdater(() => mainWindow) createWindow() diff --git a/electron/main/ipc-handlers.ts b/electron/main/ipc-handlers.ts index b2bf758..8083694 100644 --- a/electron/main/ipc-handlers.ts +++ b/electron/main/ipc-handlers.ts @@ -1,7 +1,8 @@ -import { ipcMain, BrowserWindow, dialog, app } from 'electron' +import { ipcMain, BrowserWindow, dialog, app, shell } from 'electron' +import { autoUpdater } from 'electron-updater' import { join } from 'path' import { rm as rmAsync, readFile, writeFile, mkdir, readdir, rename, cp } from 'fs/promises' -import { existsSync } from 'fs' +import { existsSync, readdirSync, statSync } from 'fs' import axios from 'axios' import tar from 'tar' import { PythonBridge, API_BASE_URL } from './python-bridge' @@ -20,6 +21,33 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe // Logging from renderer ipcMain.on('log:error', (_event, message: string) => logger.error(`[Renderer] ${message}`)) ipcMain.handle('log:getPath', () => join(app.getPath('userData'), 'logs', 'modly.log')) + ipcMain.handle('log:readAll', async (_event, session?: string) => { + const logsDir = join(app.getPath('userData'), 'logs') + const dir = session ? join(logsDir, 'sessions', session) : logsDir + const files = ['modly.log', 'errors.log', 'runtime.log'] + const result: Record = {} + for (const file of files) { + try { + const filePath = join(dir, file) + result[file] = existsSync(filePath) ? await readFile(filePath, 'utf-8') : '' + } catch { + result[file] = '' + } + } + return result + }) + ipcMain.handle('log:listSessions', () => { + const sessionsDir = join(app.getPath('userData'), 'logs', 'sessions') + if (!existsSync(sessionsDir)) return [] + try { + return readdirSync(sessionsDir) + .filter(f => statSync(join(sessionsDir, f)).isDirectory()) + .sort() + .reverse() + } catch { + return [] + } + }) // Window controls (frameless window) ipcMain.on('window:minimize', () => getWindow()?.minimize()) @@ -32,9 +60,19 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe // Setup handlers — skipped in dev (uses .venv instead of python-embed) ipcMain.handle('setup:check', async () => { - if (!app.isPackaged) return { needed: false } const userData = app.getPath('userData') - return { needed: checkSetupNeeded(userData) } + const defaultDataDir = join(app.getPath('documents'), 'Modly') + return { needed: checkSetupNeeded(userData), defaultDataDir } + }) + + ipcMain.handle('setup:saveDataDir', async (_event, { baseDir }: { baseDir: string }) => { + const userData = app.getPath('userData') + setSettings(userData, { + modelsDir: join(baseDir, 'models'), + workspaceDir: join(baseDir, 'workspace'), + extensionsDir: join(baseDir, 'extensions'), + dependenciesDir: join(baseDir, 'dependencies'), + }) }) ipcMain.handle('setup:run', async () => { @@ -96,8 +134,17 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe return result.canceled ? null : result.filePath }) + ipcMain.handle('model:unloadAll', async (): Promise<{ success: boolean; error?: string }> => { + try { + await axios.post(`${API_BASE_URL}/model/unload-all`, {}, { timeout: 10_000 }) + return { success: true } + } catch (err) { + return { success: false, error: String(err) } + } + }) + ipcMain.handle('model:delete', async (_, modelId: string): Promise<{ success: boolean; error?: string }> => { - const modelDir = join(app.getPath('userData'), 'models', modelId) + const modelDir = join(getSettings(app.getPath('userData')).modelsDir, modelId) try { await axios.post(`${API_BASE_URL}/model/unload/${encodeURIComponent(modelId)}`, {}, { timeout: 5000 }) } catch { @@ -111,6 +158,13 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe } }) + ipcMain.handle('model:showInFolder', (_, modelId: string) => { + const modelDir = join(getSettings(app.getPath('userData')).modelsDir, modelId) + if (existsSync(modelDir)) { + shell.openPath(modelDir) + } + }) + // Read local file → base64 (bypasses file:// restrictions in the renderer) ipcMain.handle('fs:readFileBase64', async (_, filePath: string) => { const buffer = await readFile(filePath) @@ -119,20 +173,20 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe // Model management ipcMain.handle('model:listDownloaded', () => { - const modelsDir = join(app.getPath('userData'), 'models') + const modelsDir = getSettings(app.getPath('userData')).modelsDir return listDownloadedModels(modelsDir) }) ipcMain.handle('model:isDownloaded', (_, modelId: string): boolean => { - const modelsDir = join(app.getPath('userData'), 'models') + const modelsDir = getSettings(app.getPath('userData')).modelsDir return isModelDownloaded(modelsDir, modelId) }) - ipcMain.handle('model:download', async (event, { repoId, modelId }: { repoId: string; modelId: string }) => { + ipcMain.handle('model:download', async (event, { repoId, modelId, skipPrefixes }: { repoId: string; modelId: string; skipPrefixes?: string[] }) => { try { - await downloadModelFromHF(repoId, modelId, (pct) => { - event.sender.send('model:downloadProgress', { modelId, percent: pct }) - }) + await downloadModelFromHF(repoId, modelId, (progress) => { + event.sender.send('model:downloadProgress', { modelId, ...progress }) + }, skipPrefixes) return { success: true } } catch (err) { return { success: false, error: String(err) } @@ -170,7 +224,7 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe ipcMain.handle('app:info', () => ({ version: app.getVersion(), userData: app.getPath('userData'), - modelsDir: join(app.getPath('userData'), 'models'), + modelsDir: getSettings(app.getPath('userData')).modelsDir, apiUrl: API_BASE_URL })) @@ -179,7 +233,7 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe return getSettings(app.getPath('userData')) }) - ipcMain.handle('settings:set', (_event, patch: { modelsDir?: string; workspaceDir?: string }) => { + ipcMain.handle('settings:set', (_event, patch: { modelsDir?: string; workspaceDir?: string; extensionsDir?: string }) => { return setSettings(app.getPath('userData'), patch) }) @@ -211,7 +265,8 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe }) // Workspace filesystem-based persistence - const workspacePath = (...parts: string[]) => join(app.getPath('userData'), 'workspace', ...parts) + const workspacePath = (...parts: string[]) => + join(getSettings(app.getPath('userData')).workspaceDir, ...parts) ipcMain.handle('workspace:listCollections', async () => { const base = workspacePath() @@ -276,10 +331,11 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe ipcMain.handle('fs:deleteDirectory', async (_, dirPath: string) => { const userData = app.getPath('userData') + const settings = getSettings(userData) const allowedRoots = [ - join(userData, 'models'), - join(userData, 'workspace'), - join(userData, 'extensions'), + settings.modelsDir, + settings.workspaceDir, + settings.extensionsDir, join(userData, 'gen-cache'), ] const resolved = join(dirPath) @@ -332,15 +388,15 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe description?: string; author?: string | { name?: string } hf_repo?: string; source?: string; generator_class?: string model?: { repoId?: string; modelId?: string } - models?: { id?: string; name?: string; hf_repo?: string; description?: string }[] + models?: { id?: string; name?: string; hf_repo?: string; description?: string; hf_skip_prefixes?: string[] }[] } function parseExtensionManifest(parsed: ParsedManifest, fallbackId: string, trustedRepos: Set) { - let models: { id: string; name: string; repoId: string; description?: string }[] = [] + let models: { id: string; name: string; repoId: string; description?: string; hfSkipPrefixes?: string[] }[] = [] if (parsed.models?.length) { models = parsed.models .filter(v => v.hf_repo && v.id) - .map(v => ({ id: v.id!, name: v.name ?? v.id!, repoId: v.hf_repo!, description: v.description })) + .map(v => ({ id: v.id!, name: v.name ?? v.id!, repoId: v.hf_repo!, description: v.description, hfSkipPrefixes: v.hf_skip_prefixes })) } else { const repoId = parsed.model?.repoId ?? parsed.hf_repo const modelId = parsed.model?.modelId ?? parsed.id ?? fallbackId @@ -358,9 +414,9 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe } } - // Extensions — reads %appdata%/Modly/extensions + // Extensions — reads configured extensions directory ipcMain.handle('extensions:list', async () => { - const extensionsDir = join(app.getPath('userData'), 'extensions') + const extensionsDir = getSettings(app.getPath('userData')).extensionsDir try { if (!existsSync(extensionsDir)) return [] const [entries, trustedRepos] = await Promise.all([ @@ -449,7 +505,7 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe await writeFile(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8') // 5. Copy to extensions directory (overwrite if already present) - const extensionsDir = join(app.getPath('userData'), 'extensions') + const extensionsDir = getSettings(app.getPath('userData')).extensionsDir await mkdir(extensionsDir, { recursive: true }) const destDir = join(extensionsDir, manifest.id) @@ -481,7 +537,7 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe // Uninstall an extension — deletes its directory and reloads Python ipcMain.handle('extensions:uninstall', async (_, extensionId: string) => { - const extensionsDir = join(app.getPath('userData'), 'extensions') + const extensionsDir = getSettings(app.getPath('userData')).extensionsDir const extPath = join(extensionsDir, extensionId) try { await rmAsync(extPath, { recursive: true, force: true }) @@ -505,12 +561,29 @@ export function setupIpcHandlers(pythonBridge: PythonBridge, getWindow: WindowGe } }) + // Auto-updater + ipcMain.handle('updater:check', async () => { + if (!app.isPackaged) return { success: false } + try { + await autoUpdater.checkForUpdates() + return { success: true } + } catch (err) { + logger.error(`[updater:check] ${err}`) + return { success: false } + } + }) + + ipcMain.handle('updater:quitAndInstall', () => { + autoUpdater.quitAndInstall(false, true) + }) + // Update FastAPI paths at runtime (without restarting) - ipcMain.handle('api:updatePaths', async (_event, patch: { modelsDir?: string; workspaceDir?: string }) => { + ipcMain.handle('api:updatePaths', async (_event, patch: { modelsDir?: string; workspaceDir?: string; extensionsDir?: string }) => { try { await axios.post(`${API_BASE_URL}/settings/paths`, { - models_dir: patch.modelsDir, - workspace_dir: patch.workspaceDir, + models_dir: patch.modelsDir, + workspace_dir: patch.workspaceDir, + extensions_dir: patch.extensionsDir, }) return { success: true } } catch (err) { diff --git a/electron/main/logger.ts b/electron/main/logger.ts index 09efd8b..c5da2ea 100644 --- a/electron/main/logger.ts +++ b/electron/main/logger.ts @@ -1,8 +1,9 @@ import { app } from 'electron' -import { appendFileSync, mkdirSync, existsSync, statSync, renameSync } from 'fs' +import { appendFileSync, mkdirSync, existsSync, readdirSync, statSync, renameSync, rmSync } from 'fs' import { join } from 'path' -const MAX_SIZE_BYTES = 5 * 1024 * 1024 // 5 MB +const MAX_SESSIONS = 10 +const LOG_FILES = ['modly.log', 'errors.log', 'runtime.log'] function getLogsDir(): string { const logsDir = join(app.getPath('userData'), 'logs') @@ -10,19 +11,9 @@ function getLogsDir(): string { return logsDir } -function rotate(logPath: string): void { +function writeTo(filename: string, logLine: string): void { try { - if (existsSync(logPath) && statSync(logPath).size > MAX_SIZE_BYTES) { - renameSync(logPath, logPath.replace('.log', '.old.log')) - } - } catch {} -} - -function writeTo(filename: string, line: string): void { - try { - const logPath = join(getLogsDir(), filename) - rotate(logPath) - appendFileSync(logPath, line, 'utf-8') + appendFileSync(join(getLogsDir(), filename), logLine, 'utf-8') } catch {} } @@ -30,6 +21,35 @@ function line(level: string, message: string): string { return `[${new Date().toISOString()}] [${level}] ${message}\n` } +export function archiveCurrentSession(): void { + const logsDir = getLogsDir() + const hasLogs = LOG_FILES.some(f => existsSync(join(logsDir, f))) + if (!hasLogs) return + + const timestamp = new Date().toISOString().replace(/:/g, '-').slice(0, 19) + const sessionsDir = join(logsDir, 'sessions') + const sessionDir = join(sessionsDir, timestamp) + mkdirSync(sessionDir, { recursive: true }) + + for (const file of LOG_FILES) { + const src = join(logsDir, file) + if (existsSync(src)) { + try { renameSync(src, join(sessionDir, file)) } catch {} + } + } + + // Keep only last MAX_SESSIONS + try { + const sessions = readdirSync(sessionsDir) + .filter(f => statSync(join(sessionsDir, f)).isDirectory()) + .sort() + .reverse() + for (const old of sessions.slice(MAX_SESSIONS)) { + rmSync(join(sessionsDir, old), { recursive: true, force: true }) + } + } catch {} +} + export const logger = { info: (msg: string) => { console.log(msg); writeTo('modly.log', line('INFO', msg)) }, warn: (msg: string) => { console.warn(msg); writeTo('modly.log', line('WARN', msg)) }, diff --git a/electron/main/model-downloader.ts b/electron/main/model-downloader.ts index 8a3f478..544adfd 100644 --- a/electron/main/model-downloader.ts +++ b/electron/main/model-downloader.ts @@ -5,7 +5,14 @@ import { existsSync, readdirSync, statSync, readFileSync } from 'fs' import { join } from 'path' -export type ProgressCallback = (percent: number) => void +export interface DownloadProgress { + percent: number + file?: string + fileIndex?: number + totalFiles?: number + status?: string +} +export type ProgressCallback = (progress: DownloadProgress) => void const PYTHON_API_URL = process.env['PYTHON_API_URL'] ?? 'http://127.0.0.1:8765' @@ -99,12 +106,16 @@ export function listDownloadedModels(modelsDir: string): { id: string; name: str * Reports progress (0–100) via the onProgress callback. */ export async function downloadModelFromHF( - repoId: string, - modelId: string, - onProgress: ProgressCallback + repoId: string, + modelId: string, + onProgress: ProgressCallback, + skipPrefixes?: string[], ): Promise { const { net } = require('electron') - const url = `${PYTHON_API_URL}/model/hf-download?repo_id=${encodeURIComponent(repoId)}&model_id=${encodeURIComponent(modelId)}` + let url = `${PYTHON_API_URL}/model/hf-download?repo_id=${encodeURIComponent(repoId)}&model_id=${encodeURIComponent(modelId)}` + if (skipPrefixes && skipPrefixes.length > 0) { + url += `&skip_prefixes=${encodeURIComponent(JSON.stringify(skipPrefixes))}` + } const res = await net.fetch(url) if (!res.ok) throw new Error(`HuggingFace download failed: HTTP ${res.status}`) @@ -126,7 +137,13 @@ export async function downloadModelFromHF( if (!line.startsWith('data: ')) continue try { const data = JSON.parse(line.slice(6)) - if (typeof data.percent === 'number') onProgress(data.percent) + if (typeof data.percent === 'number') onProgress({ + percent: data.percent, + file: data.file, + fileIndex: data.fileIndex, + totalFiles: data.totalFiles, + status: data.status, + }) if (data.error) throw new Error(`HF download error: ${data.error}`) } catch (e) { if (e instanceof Error && e.message.startsWith('HF download error:')) throw e diff --git a/electron/main/python-bridge.ts b/electron/main/python-bridge.ts index 2664f29..d04d028 100644 --- a/electron/main/python-bridge.ts +++ b/electron/main/python-bridge.ts @@ -5,6 +5,7 @@ import { existsSync, mkdirSync } from 'fs' import axios from 'axios' import { getSettings } from './settings-store' import { logger } from './logger' +import { cleanPythonEnv, getVenvPythonExe } from './python-setup' const API_PORT = 8765 const API_HOST = '127.0.0.1' @@ -15,18 +16,15 @@ export class PythonBridge { private ready = false private startPromise: Promise | null = null private getWindow: (() => BrowserWindow | null) | null = null + private intentionalStop = false setWindowGetter(fn: () => BrowserWindow | null): void { this.getWindow = fn } async start(): Promise { - // Already fully ready if (this.ready) return - - // Startup already in progress — wait for the same promise instead of spawning again if (this.startPromise) return this.startPromise - this.startPromise = this._start() try { await this.startPromise @@ -37,7 +35,6 @@ export class PythonBridge { private async _start(): Promise { if (this.process) { - // Process spawned but not ready yet (e.g. second concurrent call) — just wait await this.waitUntilReady() return } @@ -53,8 +50,9 @@ export class PythonBridge { this.process = spawn(pythonExecutable, ['-m', 'uvicorn', 'main:app', '--host', API_HOST, '--port', String(API_PORT)], { cwd: apiDir, env: { - ...process.env, + ...cleanPythonEnv(), PYTHONUNBUFFERED: '1', + // No PYTHONPATH needed — the venv's Python has its own isolated site-packages MODELS_DIR: this.resolveModelsDir(), WORKSPACE_DIR: this.resolveWorkspaceDir(), EXTENSIONS_DIR: this.resolveExtensionsDir(), @@ -81,21 +79,19 @@ export class PythonBridge { console.log('[PythonBridge] Process exited with code', code) this.ready = false this.process = null - if (wasReady) { - // Server crashed while running — notify the renderer so it stops making API calls + if (wasReady && !this.intentionalStop) { this.getWindow()?.webContents.send('python:crashed', { code }) } }) await this.waitUntilReady() - } // ← end of _start() + } async stop(): Promise { if (!this.process) return const proc = this.process this.process = null this.ready = false - // On Windows, taskkill /T kills the process AND all its children if (process.platform === 'win32') { const { execSync } = require('child_process') try { execSync(`taskkill /PID ${proc.pid} /T /F`) } catch {} @@ -105,21 +101,22 @@ export class PythonBridge { console.log('[PythonBridge] Stopped') } + async restart(): Promise { + console.log('[PythonBridge] Restarting to free memory…') + this.intentionalStop = true + await this.stop() + this.intentionalStop = false + await this.start() + } + private emitTqdmLog(raw: string): void { - // Skip uvicorn HTTP access logs and Python INFO logger lines if (/INFO/.test(raw)) return - // Skip empty lines if (!raw.trim()) return this.getWindow()?.webContents.send('python:log', raw.trim()) } - isReady(): boolean { - return this.ready - } - - getPort(): number { - return API_PORT - } + isReady(): boolean { return this.ready } + getPort(): number { return API_PORT } private async killProcessOnPort(): Promise { const { execSync } = require('child_process') @@ -129,43 +126,29 @@ export class PythonBridge { return } - // Retry loop — after a kill the port may take a few ms to be released for (let attempt = 0; attempt < 3; attempt++) { let output = '' try { - // ":8765 " with trailing space avoids matching :87650, :87651, etc. - output = execSync( - `netstat -ano | findstr ":${API_PORT} "`, - { encoding: 'utf8', shell: true } - ) as string - } catch { - break // findstr returns exit code 1 when no match — port is free - } + output = execSync(`netstat -ano | findstr ":${API_PORT} "`, { encoding: 'utf8', shell: true }) as string + } catch { break } const pids = new Set() for (const line of output.split('\n')) { const match = line.trim().match(/\s+(\d+)$/) if (match && match[1] !== '0') pids.add(match[1]) } - if (pids.size === 0) break for (const pid of pids) { - try { - execSync(`taskkill /PID ${pid} /T /F`, { shell: true }) - console.log(`[PythonBridge] Killed process tree PID ${pid} on port ${API_PORT}`) - } catch {} + try { execSync(`taskkill /PID ${pid} /T /F`, { shell: true }) } catch {} } - await new Promise((r) => setTimeout(r, 300)) } } private async waitUntilReady(maxRetries = 180, delayMs = 500): Promise { for (let i = 0; i < maxRetries; i++) { - if (!this.process) { - throw new Error('FastAPI process exited unexpectedly during startup') - } + if (!this.process) throw new Error('FastAPI process exited unexpectedly during startup') try { await axios.get(`${API_BASE_URL}/health`, { timeout: 2000 }) this.ready = true @@ -179,40 +162,31 @@ export class PythonBridge { } private resolvePythonExecutable(): string { - const apiDir = this.resolveApiDir() - const resourcesPath = app.isPackaged - ? process.resourcesPath - : join(app.getAppPath(), 'resources') const userData = app.getPath('userData') + const apiDir = this.resolveApiDir() - const candidates = app.isPackaged - ? [ - join(resourcesPath, 'python-embed', 'python.exe'), // Windows embeddable - join(userData, 'venv', 'bin', 'python'), // Linux/macOS venv (packaged) - 'python3', - 'python', - ] - : [ - join(apiDir, '.venv', 'Scripts', 'python.exe'), // Windows venv (dev) - join(apiDir, '.venv', 'bin', 'python'), // Unix/Mac venv (dev) - 'python', - 'python3', - ] - - for (const candidate of candidates) { - if (existsSync(candidate)) { - return candidate - } + // Primary: venv created during setup (bundled Python → isolated venv) + const venvPython = getVenvPythonExe(userData) + if (existsSync(venvPython)) return venvPython + + // Dev fallback: local .venv in the api directory + const devCandidates = [ + join(apiDir, '.venv', 'Scripts', 'python.exe'), + join(apiDir, '.venv', 'bin', 'python'), + ] + for (const c of devCandidates) { + if (existsSync(c)) return c } - return process.platform === 'win32' ? 'python' : 'python3' + // Never fall back to bare 'python' on Windows — it would be the user's system Python + if (process.platform === 'win32') { + throw new Error('Python venv not found. Please restart the application to re-run setup.') + } + return 'python3' } private resolveApiDir(): string { - if (app.isPackaged) { - return join(process.resourcesPath, 'api') - } - // In dev, app.getAppPath() returns the desktop/ folder + if (app.isPackaged) return join(process.resourcesPath, 'api') return join(app.getAppPath(), 'api') } @@ -229,9 +203,8 @@ export class PythonBridge { } private resolveExtensionsDir(): string { - const dir = join(app.getPath('userData'), 'extensions') - mkdirSync(dir, { recursive: true }) - return dir + const s = getSettings(app.getPath('userData')) + mkdirSync(s.extensionsDir, { recursive: true }) + return s.extensionsDir } - } diff --git a/electron/main/python-setup.ts b/electron/main/python-setup.ts index 09c0fd4..197a001 100644 --- a/electron/main/python-setup.ts +++ b/electron/main/python-setup.ts @@ -1,11 +1,11 @@ import { BrowserWindow, app } from 'electron' -import { existsSync, readFileSync, writeFileSync, readdirSync } from 'fs' +import { existsSync, readFileSync, writeFileSync } from 'fs' import { join } from 'path' import { spawn, execSync } from 'child_process' import { createHash } from 'crypto' +import { getSettings } from './settings-store' -const SETUP_VERSION = 2 -const TOTAL_PACKAGES = 20 +const SETUP_VERSION = 3 interface SetupJson { version: number @@ -27,7 +27,53 @@ function hashRequirements(): string { } } -// ─── Public helpers ────────────────────────────────────────────────────────── +// ─── Environment ───────────────────────────────────────────────────────────── + +/** + * Clean environment for spawning Python/pip. + * Strips vars that could redirect imports or installs to the user's system Python. + */ +export function cleanPythonEnv(): NodeJS.ProcessEnv { + const { + PYTHONHOME, PYTHONPATH, PYTHONSTARTUP, PYTHONUSERBASE, + PIP_USER, PIP_TARGET, PIP_PREFIX, PIP_REQUIRE_VIRTUALENV, + VIRTUAL_ENV, CONDA_PREFIX, + ...rest + } = process.env + void PYTHONHOME; void PYTHONPATH; void PYTHONSTARTUP; void PYTHONUSERBASE + void PIP_USER; void PIP_TARGET; void PIP_PREFIX; void PIP_REQUIRE_VIRTUALENV + void VIRTUAL_ENV; void CONDA_PREFIX + return rest +} + +// ─── Path helpers ───────────────────────────────────────────────────────────── + +export function getEmbeddedPythonDir(): string { + if (app.isPackaged) return join(process.resourcesPath, 'python-embed') + return join(app.getAppPath(), 'resources', 'python-embed') +} + +export function getEmbeddedPythonExe(): string { + const dir = getEmbeddedPythonDir() + return process.platform === 'win32' ? join(dir, 'python.exe') : join(dir, 'bin', 'python3') +} + +/** Venv lives inside dependenciesDir on Windows (user-configurable drive), userData on Linux. */ +export function getVenvDir(userData: string): string { + if (process.platform === 'win32') { + return join(getSettings(userData).dependenciesDir, 'venv') + } + return join(userData, 'venv') +} + +export function getVenvPythonExe(userData: string): string { + const venvDir = getVenvDir(userData) + return process.platform === 'win32' + ? join(venvDir, 'Scripts', 'python.exe') + : join(venvDir, 'bin', 'python') +} + +// ─── Setup state ────────────────────────────────────────────────────────────── export function checkSetupNeeded(userData: string): boolean { const jsonPath = join(userData, 'python_setup.json') @@ -39,89 +85,53 @@ export function checkSetupNeeded(userData: string): boolean { } catch { return true } - // On Unix packaged: also verify the venv was created - if (process.platform !== 'win32' && app.isPackaged) { - if (!existsSync(join(userData, 'venv', 'bin', 'python'))) return true - } + if (!existsSync(getVenvPythonExe(userData))) return true return false } export function markSetupDone(userData: string): void { - const jsonPath = join(userData, 'python_setup.json') writeFileSync( - jsonPath, + join(userData, 'python_setup.json'), JSON.stringify({ version: SETUP_VERSION, requirementsHash: hashRequirements() }), 'utf-8' ) } -/** Path to the venv Python executable created during setup (packaged Unix). */ -export function getVenvPythonExe(userData: string): string { - return join(userData, 'venv', 'bin', 'python') -} - -// ─── Embedded Python helpers (all platforms) ───────────────────────────────── - -export function getEmbeddedPythonDir(): string { - if (app.isPackaged) return join(process.resourcesPath, 'python-embed') - return join(app.getAppPath(), 'resources', 'python-embed') -} - -export function getEmbeddedPythonExe(): string { - const dir = getEmbeddedPythonDir() - if (process.platform === 'win32') return join(dir, 'python.exe') - return join(dir, 'bin', 'python3') -} +// ─── Setup steps ───────────────────────────────────────────────────────────── -function enableSitePackages(pythonDir: string, win: BrowserWindow): void { - win.webContents.send('setup:progress', { step: 'enabling-site', percent: 5 }) - const files = readdirSync(pythonDir) as string[] - const pthFile = files.find((f) => f.match(/^python\d+\._pth$/)) - if (!pthFile) { - console.warn('[PythonSetup] No ._pth file found in', pythonDir) - return - } - const pthPath = join(pythonDir, pthFile) - let content = readFileSync(pthPath, 'utf-8') - content = content.replace(/^#import site/m, 'import site') - if (!content.includes('Lib\\site-packages')) { - content = content.trimEnd() + '\nLib\\site-packages\n' - } - writeFileSync(pthPath, content, 'utf-8') - console.log('[PythonSetup] Enabled site-packages in', pthFile) -} - -function installPip(pythonExe: string, resourcesPath: string, win: BrowserWindow): Promise { +function createVenv(pythonExe: string, venvDir: string, win: BrowserWindow): Promise { return new Promise((resolve, reject) => { - win.webContents.send('setup:progress', { step: 'pip', percent: 10 }) - const getPipPath = join(resourcesPath, 'get-pip.py') - console.log('[PythonSetup] Installing pip from', getPipPath) - const proc = spawn(pythonExe, [getPipPath, '--no-warn-script-location'], { + win.webContents.send('setup:progress', { step: 'venv', percent: 5 }) + console.log('[PythonSetup] Creating venv at', venvDir) + const proc = spawn(pythonExe, ['-m', 'venv', venvDir], { stdio: ['ignore', 'pipe', 'pipe'], + env: cleanPythonEnv(), }) - proc.stdout?.on('data', (d: Buffer) => console.log('[pip install]', d.toString().trim())) - proc.stderr?.on('data', (d: Buffer) => console.error('[pip install]', d.toString().trim())) + proc.stdout?.on('data', (d: Buffer) => console.log('[venv]', d.toString().trim())) + proc.stderr?.on('data', (d: Buffer) => console.error('[venv]', d.toString().trim())) proc.on('close', (code) => { - win.webContents.send('setup:progress', { step: 'pip', percent: 20 }) - if (code === 0) resolve() - else reject(new Error(`get-pip.py exited with code ${code}`)) + if (code === 0) { + win.webContents.send('setup:progress', { step: 'venv', percent: 20 }) + resolve() + } else { + reject(new Error(`python -m venv exited with code ${code}`)) + } }) }) } -// ─── Shared helper ─────────────────────────────────────────────────────────── - function installRequirements( pythonExe: string, requirementsPath: string, win: BrowserWindow ): Promise { + const TOTAL_PACKAGES = 20 return new Promise((resolve, reject) => { - console.log('[PythonSetup] Installing requirements from', requirementsPath) + console.log('[PythonSetup] Installing requirements with', pythonExe) const proc = spawn( pythonExe, ['-m', 'pip', 'install', '-r', requirementsPath, '--no-warn-script-location', '--progress-bar', 'off'], - { stdio: ['ignore', 'pipe', 'pipe'] } + { stdio: ['ignore', 'pipe', 'pipe'], env: cleanPythonEnv() } ) let packagesInstalled = 0 const onLine = (line: string) => { @@ -160,7 +170,7 @@ function installRequirements( }) } -// ─── Unix helpers (venv) ───────────────────────────────────────────────────── +// ─── Unix dev helper ───────────────────────────────────────────────────────── function findSystemPython(): string { const candidates = ['python3.12', 'python3.11', 'python3.10', 'python3', 'python'] @@ -171,7 +181,7 @@ function findSystemPython(): string { console.log(`[PythonSetup] Found system Python: ${cmd} → ${out}`) return cmd } - } catch { /* not found, try next */ } + } catch { /* not found */ } } throw new Error( 'Python 3 not found on your system.\n' + @@ -181,57 +191,34 @@ function findSystemPython(): string { ) } -function createVenv(python3: string, venvDir: string, win: BrowserWindow): Promise { - return new Promise((resolve, reject) => { - win.webContents.send('setup:progress', { step: 'venv', percent: 10 }) - console.log('[PythonSetup] Creating venv at', venvDir) - const proc = spawn(python3, ['-m', 'venv', venvDir], { stdio: ['ignore', 'pipe', 'pipe'] }) - proc.stdout?.on('data', (d: Buffer) => console.log('[venv]', d.toString().trim())) - proc.stderr?.on('data', (d: Buffer) => console.error('[venv]', d.toString().trim())) - proc.on('close', (code) => { - if (code === 0) { - win.webContents.send('setup:progress', { step: 'venv', percent: 20 }) - resolve() - } else { - reject(new Error(`python3 -m venv exited with code ${code}`)) - } - }) - }) -} - -// ─── Public orchestrator ───────────────────────────────────────────────────── +// ─── Public orchestrator ────────────────────────────────────────────────────── export async function runFullSetup(win: BrowserWindow, userData: string): Promise { try { const requirementsPath = getRequirementsPath() + const venvDir = getVenvDir(userData) - if (process.platform === 'win32') { - // Windows: use embedded Python bundled with the app - const pythonDir = getEmbeddedPythonDir() + if (process.platform === 'win32' || app.isPackaged) { + // Packaged (all platforms) + Windows dev: use bundled python-build-standalone. + // python-build-standalone is a full Python install → venv module works natively, + // DLLs come from the installer so SAC doesn't block them. const pythonExe = getEmbeddedPythonExe() - const resourcesPath = app.isPackaged - ? process.resourcesPath - : join(app.getAppPath(), 'resources') - - enableSitePackages(pythonDir, win) - await installPip(pythonExe, resourcesPath, win) - await installRequirements(pythonExe, requirementsPath, win) - } else if (app.isPackaged) { - // Linux / macOS packaged: use bundled Python to create a venv in userData - // (resources dir may be read-only inside .app bundle) - win.webContents.send('setup:progress', { step: 'venv', percent: 5 }) - const python3 = getEmbeddedPythonExe() - const venvDir = join(userData, 'venv') - await createVenv(python3, venvDir, win) - const venvPython = join(venvDir, 'bin', 'python') + if (!existsSync(pythonExe)) { + throw new Error( + 'Bundled Python runtime not found.\n' + + 'Please reinstall the application.\n' + + `(expected: ${pythonExe})` + ) + } + await createVenv(pythonExe, venvDir, win) + const venvPython = getVenvPythonExe(userData) await installRequirements(venvPython, requirementsPath, win) } else { - // Linux / macOS dev: create a venv using the system Python - win.webContents.send('setup:progress', { step: 'python', percent: 5 }) + // Linux / macOS dev: use system Python + win.webContents.send('setup:progress', { step: 'venv', percent: 5 }) const python3 = findSystemPython() - const venvDir = join(userData, 'venv') await createVenv(python3, venvDir, win) - const venvPython = join(venvDir, 'bin', 'python') + const venvPython = getVenvPythonExe(userData) await installRequirements(venvPython, requirementsPath, win) } diff --git a/electron/main/settings-store.ts b/electron/main/settings-store.ts index 3186b16..177eea1 100644 --- a/electron/main/settings-store.ts +++ b/electron/main/settings-store.ts @@ -2,8 +2,10 @@ import { join } from 'path' import { readFileSync, writeFileSync, existsSync } from 'fs' export interface AppSettings { - modelsDir: string - workspaceDir: string + modelsDir: string + workspaceDir: string + extensionsDir: string + dependenciesDir: string } function settingsPath(userData: string): string { @@ -12,8 +14,10 @@ function settingsPath(userData: string): string { export function getSettings(userData: string): AppSettings { const defaults: AppSettings = { - modelsDir: join(userData, 'models'), - workspaceDir: join(userData, 'workspace'), + modelsDir: join(userData, 'models'), + workspaceDir: join(userData, 'workspace'), + extensionsDir: join(userData, 'extensions'), + dependenciesDir: join(userData, 'dependencies'), } const file = settingsPath(userData) diff --git a/electron/main/updater.ts b/electron/main/updater.ts new file mode 100644 index 0000000..262748b --- /dev/null +++ b/electron/main/updater.ts @@ -0,0 +1,43 @@ +import { app, BrowserWindow } from 'electron' +import { autoUpdater } from 'electron-updater' +import { logger } from './logger' + +type WindowGetter = () => BrowserWindow | null + +export function initAutoUpdater(getWindow: WindowGetter): void { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + autoUpdater.logger = logger as any + autoUpdater.autoDownload = false + autoUpdater.autoInstallOnAppQuit = true + + autoUpdater.on('update-available', (info) => { + const running = app.getVersion() + const incoming = info.version + const [rMaj, rMin] = running.split('.').map(Number) + const [iMaj, iMin] = incoming.split('.').map(Number) + const isPatch = rMaj === iMaj && rMin === iMin + + if (isPatch) { + logger.info(`[updater] Patch update ${incoming} available — downloading silently`) + autoUpdater.downloadUpdate().catch((err: Error) => { + logger.error(`[updater] Download failed: ${err.message}`) + }) + } else { + logger.info(`[updater] Major/minor update ${incoming} available — notifying renderer`) + getWindow()?.webContents.send('updater:major-minor-available', { version: incoming }) + } + }) + + autoUpdater.on('update-downloaded', (info) => { + logger.info(`[updater] Patch update ${info.version} downloaded — showing badge`) + getWindow()?.webContents.send('updater:patch-ready', { version: info.version }) + }) + + autoUpdater.on('update-not-available', () => { + logger.info('[updater] App is up to date') + }) + + autoUpdater.on('error', (err: Error) => { + logger.error(`[updater] Error: ${err.message}`) + }) +} diff --git a/electron/preload/index.ts b/electron/preload/index.ts index a78bab1..ba80015 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -45,9 +45,9 @@ contextBridge.exposeInMainWorld('electron', { // Settings settings: { - get: (): Promise<{ modelsDir: string; workspaceDir: string }> => + get: (): Promise<{ modelsDir: string; workspaceDir: string; extensionsDir: string }> => ipcRenderer.invoke('settings:get'), - set: (patch: { modelsDir?: string; workspaceDir?: string }): Promise<{ modelsDir: string; workspaceDir: string }> => + set: (patch: { modelsDir?: string; workspaceDir?: string; extensionsDir?: string }): Promise<{ modelsDir: string; workspaceDir: string; extensionsDir: string }> => ipcRenderer.invoke('settings:set', patch), }, @@ -59,7 +59,7 @@ contextBridge.exposeInMainWorld('electron', { // API helpers (calls FastAPI from the main process) api: { - updatePaths: (patch: { modelsDir?: string; workspaceDir?: string }): Promise<{ success: boolean; error?: string }> => + updatePaths: (patch: { modelsDir?: string; workspaceDir?: string; extensionsDir?: string }): Promise<{ success: boolean; error?: string }> => ipcRenderer.invoke('api:updatePaths', patch), }, @@ -68,9 +68,11 @@ contextBridge.exposeInMainWorld('electron', { export: (args: { outputUrl: string; format: string }) => ipcRenderer.invoke('model:export', args), listDownloaded: () => ipcRenderer.invoke('model:listDownloaded'), isDownloaded: (modelId: string) => ipcRenderer.invoke('model:isDownloaded', modelId), - download: (repoId: string, modelId: string) => ipcRenderer.invoke('model:download', { repoId, modelId }), + download: (repoId: string, modelId: string, skipPrefixes?: string[]) => ipcRenderer.invoke('model:download', { repoId, modelId, skipPrefixes }), delete: (modelId: string) => ipcRenderer.invoke('model:delete', modelId), - onProgress: (cb: (data: { modelId: string; percent: number }) => void) => { + unloadAll: () => ipcRenderer.invoke('model:unloadAll'), + showInFolder: (modelId: string) => ipcRenderer.invoke('model:showInFolder', modelId), + onProgress: (cb: (data: { modelId: string; percent: number; file?: string; fileIndex?: number; totalFiles?: number; status?: string }) => void) => { ipcRenderer.on('model:downloadProgress', (_event, data) => cb(data)) }, offProgress: () => ipcRenderer.removeAllListeners('model:downloadProgress') @@ -79,13 +81,19 @@ contextBridge.exposeInMainWorld('electron', { // App metadata app: { info: (): Promise<{ version: string; userData: string; modelsDir: string; apiUrl: string }> => - ipcRenderer.invoke('app:info') + ipcRenderer.invoke('app:info'), + onError: (cb: (message: string) => void) => { + ipcRenderer.on('app:error', (_event, message) => cb(message)) + }, + offError: () => ipcRenderer.removeAllListeners('app:error'), }, // Logging log: { error: (message: string) => ipcRenderer.send('log:error', message), getPath: (): Promise => ipcRenderer.invoke('log:getPath'), + readAll: (session?: string): Promise> => ipcRenderer.invoke('log:readAll', session), + listSessions: (): Promise => ipcRenderer.invoke('log:listSessions'), }, // Workspace filesystem-based persistence @@ -142,12 +150,30 @@ contextBridge.exposeInMainWorld('electron', { offInstallProgress: () => ipcRenderer.removeAllListeners('extensions:installProgress'), }, + // Auto-updater + updater: { + check: (): Promise<{ success: boolean }> => + ipcRenderer.invoke('updater:check'), + quitAndInstall: (): Promise => + ipcRenderer.invoke('updater:quitAndInstall'), + onPatchReady: (cb: (data: { version: string }) => void) => { + ipcRenderer.on('updater:patch-ready', (_event, data) => cb(data)) + }, + offPatchReady: () => ipcRenderer.removeAllListeners('updater:patch-ready'), + onMajorMinorAvailable: (cb: (data: { version: string }) => void) => { + ipcRenderer.on('updater:major-minor-available', (_event, data) => cb(data)) + }, + offMajorMinorAvailable: () => ipcRenderer.removeAllListeners('updater:major-minor-available'), + }, + // First-run setup setup: { - check: (): Promise<{ needed: boolean }> => + check: (): Promise<{ needed: boolean; defaultDataDir: string }> => ipcRenderer.invoke('setup:check'), - run: (): Promise<{ success: boolean; error?: string }> => + run: (): Promise<{ success: boolean; error?: string }> => ipcRenderer.invoke('setup:run'), + saveDataDir: (baseDir: string): Promise => + ipcRenderer.invoke('setup:saveDataDir', { baseDir }), onProgress: (cb: (data: { step: string; percent: number; currentPackage?: string }) => void) => { ipcRenderer.on('setup:progress', (_e, data) => cb(data)) }, diff --git a/package-lock.json b/package-lock.json index 9af5939..da58bda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,18 @@ { - "name": "local-meshy", - "version": "0.1.0", + "name": "modly", + "version": "0.1.4", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "local-meshy", - "version": "0.1.0", + "name": "modly", + "version": "0.1.4", "dependencies": { "@electron-toolkit/utils": "^4.0.0", "@react-three/drei": "^9.120.0", "@react-three/fiber": "^8.17.10", "axios": "^1.7.9", + "electron-updater": "^6.8.3", "react": "^18.3.1", "react-dom": "^18.3.1", "tar": "^7.5.9", @@ -28,7 +29,7 @@ "autoprefixer": "^10.4.20", "cross-env": "^10.1.0", "electron": "^33.3.0", - "electron-builder": "^25.1.8", + "electron-builder": "^24.13.3", "electron-vite": "^2.3.0", "eslint": "^9.17.0", "postcss": "^8.4.49", @@ -340,6 +341,7 @@ "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.0", "ajv-keywords": "^3.4.1" @@ -365,6 +367,7 @@ "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz", "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", "dev": true, + "license": "MIT", "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", @@ -377,27 +380,23 @@ "node": ">=10.12.0" } }, - "node_modules/@electron/asar/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, "node_modules/@electron/asar/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/asar/node_modules/minimatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz", - "integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -426,10 +425,11 @@ } }, "node_modules/@electron/notarize": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz", - "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.2.1.tgz", + "integrity": "sha512-aL+bFMIkpR0cmmj5Zgy0LMKEpgy43/hw5zadEArgmAMWWlKc5buwFvFT9G/o/YJkvXAJm5q3iuTuLaiaXW39sg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.1", @@ -444,6 +444,7 @@ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, + "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -459,6 +460,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -471,15 +473,17 @@ "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", - "integrity": "sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.0.5.tgz", + "integrity": "sha512-k9ZzUQtamSoweGQDV2jILiRIHUu7lYlJ3c6IEmjv1hC17rclE+eb9U+f6UFlOOETo0JzY1HNlXy4YOlCvl+Lww==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "compare-version": "^0.1.2", "debug": "^4.3.4", @@ -501,6 +505,7 @@ "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", @@ -515,6 +520,7 @@ "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8.0.0" }, @@ -527,6 +533,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -539,148 +546,55 @@ "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": "3.6.1", - "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.6.1.tgz", - "integrity": "sha512-f6596ZHpEq/YskUd8emYvOUne89ij8mQgjYFA5ru25QwbrRO+t1SImofdDv7kKOuWCmVOuU5tvfkbgGxIl3E/w==", - "dev": true, - "dependencies": { - "@malept/cross-spawn-promise": "^2.0.0", - "chalk": "^4.0.0", - "debug": "^4.1.1", - "detect-libc": "^2.0.1", - "fs-extra": "^10.0.0", - "got": "^11.7.0", - "node-abi": "^3.45.0", - "node-api-version": "^0.2.0", - "node-gyp": "^9.0.0", - "ora": "^5.1.0", - "read-binary-file-arch": "^1.0.6", - "semver": "^7.3.5", - "tar": "^6.0.5", - "yargs": "^17.0.1" - }, - "bin": { - "electron-rebuild": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - } - }, - "node_modules/@electron/rebuild/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, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron/rebuild/node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/rebuild/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@electron/rebuild/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@electron/rebuild/node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "node_modules/@electron/universal": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-1.5.1.tgz", + "integrity": "sha512-kbgXxyEauPJiQQUNG2VgUeyfQNFk6hBF11ISN2PNI6agUgPl55pv4eQmaqHzTAzchBvqZ2tQuRVaPStGf0mxGw==", "dev": true, + "license": "MIT", "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "@electron/asar": "^3.2.1", + "@malept/cross-spawn-promise": "^1.1.0", + "debug": "^4.3.1", + "dir-compare": "^3.0.0", + "fs-extra": "^9.0.1", + "minimatch": "^3.0.4", + "plist": "^3.0.4" }, "engines": { - "node": ">=10" - } - }, - "node_modules/@electron/rebuild/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, - "engines": { - "node": ">= 10.0.0" + "node": ">=8.6" } }, - "node_modules/@electron/rebuild/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@electron/universal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.1.tgz", - "integrity": "sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==", + "node_modules/@electron/universal/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": { - "@electron/asar": "^3.2.7", - "@malept/cross-spawn-promise": "^2.0.0", - "debug": "^4.3.1", - "dir-compare": "^4.2.0", - "fs-extra": "^11.1.1", - "minimatch": "^9.0.3", - "plist": "^3.1.0" - }, - "engines": { - "node": ">=16.4" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/@electron/universal/node_modules/fs-extra": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", - "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, + "license": "MIT", "dependencies": { + "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" }, "engines": { - "node": ">=14.14" + "node": ">=10" } }, "node_modules/@electron/universal/node_modules/jsonfile": { @@ -688,6 +602,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -696,18 +611,16 @@ } }, "node_modules/@electron/universal/node_modules/minimatch": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.6.tgz", - "integrity": "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, "node_modules/@electron/universal/node_modules/universalify": { @@ -715,6 +628,7 @@ "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" } @@ -1147,12 +1061,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/config-array/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -1222,12 +1130,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -1284,12 +1186,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true - }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1343,6 +1239,7 @@ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -1360,6 +1257,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -1372,6 +1270,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -1383,13 +1282,15 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -1403,12 +1304,13 @@ } }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" @@ -1422,6 +1324,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -1499,9 +1402,9 @@ } }, "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", - "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", + "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", "dev": true, "funding": [ { @@ -1513,11 +1416,12 @@ "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" } ], + "license": "Apache-2.0", "dependencies": { "cross-spawn": "^7.0.1" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 10" } }, "node_modules/@malept/flatpak-bundler": { @@ -1525,6 +1429,7 @@ "resolved": "https://registry.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.0", @@ -1540,6 +1445,7 @@ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, + "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -1555,6 +1461,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -1567,6 +1474,7 @@ "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" } @@ -1622,50 +1530,12 @@ "node": ">= 8" } }, - "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, - "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.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -2218,6 +2088,7 @@ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } @@ -2280,10 +2151,11 @@ } }, "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", "dev": true, + "license": "MIT", "dependencies": { "@types/ms": "*" } @@ -2304,6 +2176,7 @@ "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -2331,7 +2204,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { "version": "22.19.11", @@ -2351,6 +2225,7 @@ "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz", "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "@types/node": "*", @@ -2429,6 +2304,7 @@ "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.11.tgz", "integrity": "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/@types/webxr": { @@ -2491,6 +2367,7 @@ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" } @@ -2499,13 +2376,8 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", - "dev": true - }, - "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 + "dev": true, + "license": "MIT" }, "node_modules/acorn": { "version": "8.16.0", @@ -2529,37 +2401,16 @@ } }, "node_modules/agent-base": { - "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, - "engines": { - "node": ">= 14" - } - }, - "node_modules/agentkeepalive": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", - "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", - "dev": true, - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "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": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "debug": "4" }, "engines": { - "node": ">=8" + "node": ">= 6.0.0" } }, "node_modules/ajv": { @@ -2583,6 +2434,7 @@ "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" } @@ -2592,6 +2444,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2631,45 +2484,42 @@ } }, "node_modules/app-builder-bin": { - "version": "5.0.0-alpha.10", - "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-5.0.0-alpha.10.tgz", - "integrity": "sha512-Ev4jj3D7Bo+O0GPD2NMvJl+PGiBAfS7pUGawntBNpCbxtpncfUixqFj9z9Jme7V7s3LBGqsWZZP54fxBX3JKJw==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-4.0.0.tgz", + "integrity": "sha512-xwdG0FJPQMe0M0UA4Tz0zEB8rBJTRA5a476ZawAqiBkMv16GRK5xpXThOjMaEOFnZ6zabejjG4J3da0SXG63KA==", + "dev": true, + "license": "MIT" }, "node_modules/app-builder-lib": { - "version": "25.1.8", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-25.1.8.tgz", - "integrity": "sha512-pCqe7dfsQFBABC1jeKZXQWhGcCPF3rPCXDdfqVKjIeWBcXzyC1iOWZdfFhGl+S9MyE/k//DFmC6FzuGAUudNDg==", + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-24.13.3.tgz", + "integrity": "sha512-FAzX6IBit2POXYGnTCT8YHFO/lr5AapAII6zzhQO3Rw4cEDOgK+t1xhLc5tNcKlicTHlo9zxIwnYCX9X2DLkig==", "dev": true, + "license": "MIT", "dependencies": { "@develar/schema-utils": "~2.6.5", - "@electron/notarize": "2.5.0", - "@electron/osx-sign": "1.3.1", - "@electron/rebuild": "3.6.1", - "@electron/universal": "2.0.1", + "@electron/notarize": "2.2.1", + "@electron/osx-sign": "1.0.5", + "@electron/universal": "1.5.1", "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", "chromium-pickle-js": "^0.2.0", - "config-file-ts": "0.2.8-rc1", "debug": "^4.3.4", - "dotenv": "^16.4.5", - "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", - "electron-publish": "25.1.7", + "electron-publish": "24.13.1", "form-data": "^4.0.0", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "is-ci": "^3.0.0", "isbinaryfile": "^5.0.0", "js-yaml": "^4.1.0", - "json5": "^2.2.3", "lazy-val": "^1.0.5", - "minimatch": "^10.0.0", - "resedit": "^1.7.0", + "minimatch": "^5.1.1", + "read-config-file": "6.3.2", "sanitize-filename": "^1.6.3", "semver": "^7.3.8", "tar": "^6.1.12", @@ -2679,8 +2529,8 @@ "node": ">=14.0.0" }, "peerDependencies": { - "dmg-builder": "25.1.8", - "electron-builder-squirrel-windows": "25.1.8" + "dmg-builder": "24.13.3", + "electron-builder-squirrel-windows": "24.13.3" } }, "node_modules/app-builder-lib/node_modules/fs-extra": { @@ -2688,6 +2538,7 @@ "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", @@ -2702,6 +2553,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -2709,20 +2561,12 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/app-builder-lib/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/app-builder-lib/node_modules/semver": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -2736,6 +2580,7 @@ "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, + "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -2753,6 +2598,7 @@ "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" } @@ -2761,19 +2607,15 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/aproba": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", - "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/archiver": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "archiver-utils": "^2.1.0", @@ -2793,6 +2635,7 @@ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "glob": "^7.1.4", @@ -2815,6 +2658,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "core-util-is": "~1.0.0", @@ -2831,6 +2675,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/archiver-utils/node_modules/string_decoder": { @@ -2838,25 +2683,12 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -2866,14 +2698,14 @@ "node_modules/argparse": { "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 + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=0.8" @@ -2884,6 +2716,7 @@ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=8" @@ -2893,13 +2726,15 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/async-exit-hook": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -2914,6 +2749,7 @@ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, + "license": "ISC", "engines": { "node": ">= 4.0.0" } @@ -2965,13 +2801,11 @@ } }, "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "engines": { - "node": "18 || 20 || >=22" - } + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -3029,6 +2863,8 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -3054,6 +2890,8 @@ "url": "https://feross.org/support" } ], + "license": "MIT", + "peer": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -3063,13 +2901,15 @@ "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bluebird-lst": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz", "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", "dev": true, + "license": "MIT", "dependencies": { "bluebird": "^3.5.5" } @@ -3082,15 +2922,13 @@ "optional": true }, "node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "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": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -3169,29 +3007,44 @@ "node": "*" } }, + "node_modules/buffer-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/builder-util": { - "version": "25.1.7", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-25.1.7.tgz", - "integrity": "sha512-7jPjzBwEGRbwNcep0gGNpLXG9P94VA3CPAZQCzxkFXiV2GMQKlziMbY//rXPI7WKfhsvGgFXjTcXdBEwgXw9ww==", + "version": "24.13.1", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-24.13.1.tgz", + "integrity": "sha512-NhbCSIntruNDTOVI9fdXz0dihaqX2YuE1D6zZMrwiErzH4ELZHE6mdiB40wEgZNprDia+FghRFgKoAqMZRRjSA==", "dev": true, + "license": "MIT", "dependencies": { "@types/debug": "^4.1.6", "7zip-bin": "~5.2.0", - "app-builder-bin": "5.0.0-alpha.10", + "app-builder-bin": "4.0.0", "bluebird-lst": "^1.0.9", - "builder-util-runtime": "9.2.10", + "builder-util-runtime": "9.2.4", "chalk": "^4.1.2", "cross-spawn": "^7.0.3", "debug": "^4.3.4", "fs-extra": "^10.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", "is-ci": "^3.0.0", "js-yaml": "^4.1.0", "source-map-support": "^0.5.19", @@ -3200,10 +3053,11 @@ } }, "node_modules/builder-util-runtime": { - "version": "9.2.10", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz", - "integrity": "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==", + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.4.tgz", + "integrity": "sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.3.4", "sax": "^1.2.4" @@ -3217,6 +3071,7 @@ "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", @@ -3231,6 +3086,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -3243,6 +3099,7 @@ "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" } @@ -3256,124 +3113,6 @@ "node": ">=8" } }, - "node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, - "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/cacache/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "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, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "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/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==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.7.tgz", - "integrity": "sha512-FjiwU9HaHW6YB3H4a1sFudnv93lvydNjz2lmyUXR6IwKhGI+bgL3SOZrBGn6kvvX2pJvhEkGSGjyTHN47O4rqA==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacache/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -3514,6 +3253,7 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -3522,7 +3262,8 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ci-info": { "version": "3.9.0", @@ -3535,48 +3276,17 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cli-truncate": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "slice-ansi": "^3.0.0", @@ -3594,6 +3304,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -3603,15 +3314,6 @@ "node": ">=12" } }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/clone-response": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", @@ -3641,15 +3343,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "bin": { - "color-support": "bin.js" - } - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3666,6 +3359,7 @@ "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" } @@ -3675,6 +3369,7 @@ "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3684,6 +3379,7 @@ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "buffer-crc32": "^0.2.13", @@ -3702,13 +3398,14 @@ "dev": true }, "node_modules/config-file-ts": { - "version": "0.2.8-rc1", - "resolved": "https://registry.npmjs.org/config-file-ts/-/config-file-ts-0.2.8-rc1.tgz", - "integrity": "sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/config-file-ts/-/config-file-ts-0.2.6.tgz", + "integrity": "sha512-6boGVaglwblBgJqGyxm4+xCmEGcWgnWHSWHY5jad58awQhB6gftq0G8HbzU39YqCIYHMLAiL1yjwiZ36m/CL8w==", "dev": true, + "license": "MIT", "dependencies": { - "glob": "^10.3.12", - "typescript": "^5.4.3" + "glob": "^10.3.10", + "typescript": "^5.3.3" } }, "node_modules/config-file-ts/node_modules/glob": { @@ -3717,6 +3414,7 @@ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -3733,12 +3431,13 @@ } }, "node_modules/config-file-ts/node_modules/minimatch": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.6.tgz", - "integrity": "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -3752,16 +3451,11 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -3772,13 +3466,15 @@ "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 + "dev": true, + "license": "MIT" }, "node_modules/crc": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "buffer": "^5.1.0" @@ -3789,6 +3485,7 @@ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "dev": true, + "license": "Apache-2.0", "peer": true, "bin": { "crc32": "bin/crc32.njs" @@ -3816,6 +3513,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "optional": true, "dependencies": { "base64-js": "^1.3.1", @@ -3827,6 +3525,7 @@ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "crc-32": "^1.2.0", @@ -3931,18 +3630,6 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/defer-to-connect": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", @@ -3993,12 +3680,6 @@ "node": ">=0.4.0" } }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true - }, "node_modules/detect-gpu": { "version": "5.0.70", "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.70.tgz", @@ -4007,15 +3688,6 @@ "webgl-constants": "^1.1.1" } }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", @@ -4029,36 +3701,33 @@ "dev": true }, "node_modules/dir-compare": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", - "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-3.3.0.tgz", + "integrity": "sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg==", "dev": true, + "license": "MIT", "dependencies": { - "minimatch": "^3.0.5", - "p-limit": "^3.1.0 " + "buffer-equal": "^1.0.0", + "minimatch": "^3.0.4" } }, - "node_modules/dir-compare/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, "node_modules/dir-compare/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/dir-compare/node_modules/minimatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz", - "integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4073,14 +3742,15 @@ "dev": true }, "node_modules/dmg-builder": { - "version": "25.1.8", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-25.1.8.tgz", - "integrity": "sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ==", + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-24.13.3.tgz", + "integrity": "sha512-rcJUkMfnJpfCboZoOOPf4L29TRtEieHNOeAbYPWPxlaBw/Z1RKrRA86dOI9rwaI4tQSc/RD82zTNHprfUHXsoQ==", "dev": true, + "license": "MIT", "dependencies": { - "app-builder-lib": "25.1.8", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", + "app-builder-lib": "24.13.3", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" @@ -4094,6 +3764,7 @@ "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", @@ -4108,6 +3779,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -4120,6 +3792,7 @@ "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" } @@ -4129,6 +3802,7 @@ "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -4151,31 +3825,21 @@ } }, "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", + "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" + "node": ">=10" } }, "node_modules/dotenv-expand": { - "version": "11.0.7", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", - "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", "dev": true, - "dependencies": { - "dotenv": "^16.4.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } + "license": "BSD-2-Clause" }, "node_modules/draco3d": { "version": "1.5.7", @@ -4199,13 +3863,15 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ejs": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" }, @@ -4234,19 +3900,21 @@ } }, "node_modules/electron-builder": { - "version": "25.1.8", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-25.1.8.tgz", - "integrity": "sha512-poRgAtUHHOnlzZnc9PK4nzG53xh74wj2Jy7jkTrqZ0MWPoHGh1M2+C//hGeYdA+4K8w4yiVCNYoLXF7ySj2Wig==", + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-24.13.3.tgz", + "integrity": "sha512-yZSgVHft5dNVlo31qmJAe4BVKQfFdwpRw7sFp1iQglDRCDD6r22zfRJuZlhtB5gp9FHUxCMEoWGq10SkCnMAIg==", "dev": true, + "license": "MIT", "dependencies": { - "app-builder-lib": "25.1.8", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", + "app-builder-lib": "24.13.3", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", "chalk": "^4.1.2", - "dmg-builder": "25.1.8", + "dmg-builder": "24.13.3", "fs-extra": "^10.1.0", "is-ci": "^3.0.0", "lazy-val": "^1.0.5", + "read-config-file": "6.3.2", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, @@ -4259,15 +3927,16 @@ } }, "node_modules/electron-builder-squirrel-windows": { - "version": "25.1.8", - "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-25.1.8.tgz", - "integrity": "sha512-2ntkJ+9+0GFP6nAISiMabKt6eqBB0kX1QqHNWFWAXgi0VULKGisM46luRFpIBiU3u/TDmhZMM8tzvo2Abn3ayg==", + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-24.13.3.tgz", + "integrity": "sha512-oHkV0iogWfyK+ah9ZIvMDpei1m9ZRpdXcvde1wTpra2U8AFDNNpqJdnin5z+PM1GbQ5BoaKCWas2HSjtR0HwMg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "app-builder-lib": "25.1.8", + "app-builder-lib": "24.13.3", "archiver": "^5.3.1", - "builder-util": "25.1.7", + "builder-util": "24.13.1", "fs-extra": "^10.1.0" } }, @@ -4276,6 +3945,7 @@ "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", "peer": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -4291,6 +3961,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "universalify": "^2.0.0" @@ -4304,6 +3975,7 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 10.0.0" @@ -4345,14 +4017,15 @@ } }, "node_modules/electron-publish": { - "version": "25.1.7", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-25.1.7.tgz", - "integrity": "sha512-+jbTkR9m39eDBMP4gfbqglDd6UvBC7RLh5Y0MhFSsc6UkGHj9Vj9TWobxevHYMMqmoujL11ZLjfPpMX+Pt6YEg==", + "version": "24.13.1", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-24.13.1.tgz", + "integrity": "sha512-2ZgdEqJ8e9D17Hwp5LEq5mLQPjqU3lv/IALvgp+4W8VeNhryfGhYEQC/PgDPMrnWUp+l60Ou5SJLsu+k4mhQ8A==", "dev": true, + "license": "MIT", "dependencies": { "@types/fs-extra": "^9.0.11", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", "chalk": "^4.1.2", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", @@ -4364,6 +4037,7 @@ "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", @@ -4378,6 +4052,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -4390,6 +4065,7 @@ "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" } @@ -4400,18 +4076,94 @@ "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", "dev": true }, - "node_modules/electron-vite": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/electron-vite/-/electron-vite-2.3.0.tgz", - "integrity": "sha512-lsN2FymgJlp4k6MrcsphGqZQ9fKRdJKasoaiwIrAewN1tapYI/KINLdfEL7n10LuF0pPSNf/IqjzZbB5VINctg==", - "dev": true, + "node_modules/electron-updater": { + "version": "6.8.3", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.8.3.tgz", + "integrity": "sha512-Z6sgw3jgbikWKXei1ENdqFOxBP0WlXg3TtKfz0rgw2vIZFJUyI4pD7ZN7jrkm7EoMK+tcm/qTnPUdqfZukBlBQ==", + "license": "MIT", "dependencies": { - "@babel/core": "^7.24.7", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "cac": "^6.7.14", - "esbuild": "^0.21.5", - "magic-string": "^0.30.10", - "picocolors": "^1.0.1" + "builder-util-runtime": "9.5.1", + "fs-extra": "^10.1.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "lodash.escaperegexp": "^4.1.2", + "lodash.isequal": "^4.5.0", + "semver": "~7.7.3", + "tiny-typed-emitter": "^2.1.0" + } + }, + "node_modules/electron-updater/node_modules/builder-util-runtime": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.5.1.tgz", + "integrity": "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/electron-updater/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==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-updater/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-updater/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-updater/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-vite": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/electron-vite/-/electron-vite-2.3.0.tgz", + "integrity": "sha512-lsN2FymgJlp4k6MrcsphGqZQ9fKRdJKasoaiwIrAewN1tapYI/KINLdfEL7n10LuF0pPSNf/IqjzZbB5VINctg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.7", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "cac": "^6.7.14", + "esbuild": "^0.21.5", + "magic-string": "^0.30.10", + "picocolors": "^1.0.1" }, "bin": { "electron-vite": "bin/electron-vite.js" @@ -4441,17 +4193,8 @@ "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 - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "dev": true, - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } + "license": "MIT" }, "node_modules/end-of-stream": { "version": "1.4.5", @@ -4473,7 +4216,8 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/es-define-property": { "version": "1.0.1", @@ -4668,12 +4412,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -4755,12 +4493,6 @@ "node": ">=0.10.0" } }, - "node_modules/exponential-backoff": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", - "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", - "dev": true - }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -4788,6 +4520,7 @@ "engines": [ "node >=0.6.0" ], + "license": "MIT", "optional": true }, "node_modules/fast-deep-equal": { @@ -4871,15 +4604,13 @@ } }, "node_modules/filelist": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.5.tgz", - "integrity": "sha512-ct/ckWBV/9Dg3MlvCXsLcSUyoWwv9mCKqlhLNB2DAuXR/NZolSXlQqP5dyy6guWlPXBhodZyZ5lGPQcbQDxrEQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "minimatch": "^10.2.1" - }, - "engines": { - "node": "20 || >=22" + "minimatch": "^5.0.1" } }, "node_modules/fill-range": { @@ -4953,6 +4684,7 @@ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" @@ -4964,18 +4696,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/form-data": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", @@ -5009,6 +4729,7 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/fs-extra": { @@ -5029,6 +4750,7 @@ "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" }, @@ -5036,11 +4758,32 @@ "node": ">= 8" } }, + "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/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -5064,26 +4807,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -5098,6 +4821,7 @@ "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.*" } @@ -5157,6 +4881,7 @@ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -5184,27 +4909,23 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, "node_modules/glob/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/glob/node_modules/minimatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz", - "integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5360,12 +5081,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true - }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -5387,6 +5102,7 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -5399,6 +5115,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -5410,7 +5127,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/http-cache-semantics": { "version": "4.2.0", @@ -5418,16 +5136,18 @@ "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==" }, "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==", + "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": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">= 14" + "node": ">= 6" } }, "node_modules/http2-wrapper": { @@ -5443,25 +5163,17 @@ } }, "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==", + "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": "^7.1.2", + "agent-base": "6", "debug": "4" }, "engines": { - "node": ">= 14" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, - "dependencies": { - "ms": "^2.0.0" + "node": ">= 6" } }, "node_modules/iconv-corefoundation": { @@ -5469,6 +5181,7 @@ "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5486,6 +5199,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -5551,27 +5265,13 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -5581,16 +5281,8 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "dev": true, - "engines": { - "node": ">= 12" - } + "license": "ISC" }, "node_modules/is-binary-path": { "version": "2.1.0", @@ -5609,6 +5301,7 @@ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", "dev": true, + "license": "MIT", "dependencies": { "ci-info": "^3.2.0" }, @@ -5645,6 +5338,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" } @@ -5661,21 +5355,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5690,23 +5369,12 @@ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "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", "peer": true }, "node_modules/isbinaryfile": { @@ -5714,6 +5382,7 @@ "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.7.tgz", "integrity": "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 18.0.0" }, @@ -5750,6 +5419,7 @@ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -5765,6 +5435,7 @@ "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", @@ -5795,7 +5466,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -5870,13 +5540,14 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", - "dev": true + "license": "MIT" }, "node_modules/lazystream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "readable-stream": "^2.0.5" @@ -5890,6 +5561,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "core-util-is": "~1.0.0", @@ -5906,6 +5578,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/lazystream/node_modules/string_decoder": { @@ -5913,6 +5586,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "safe-buffer": "~5.1.0" @@ -5976,13 +5650,15 @@ "version": "4.17.23", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/lodash.difference": { @@ -5990,20 +5666,36 @@ "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", "dev": true, + "license": "MIT", "peer": true }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "license": "MIT" + }, "node_modules/lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", "dev": true, + "license": "MIT", "peer": true }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/lodash.merge": { @@ -6017,24 +5709,9 @@ "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", "dev": true, + "license": "MIT", "peer": true }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6081,81 +5758,6 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "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, - "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/make-fetch-happen/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, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/make-fetch-happen/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, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/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, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "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, - "engines": { - "node": ">=12" - } - }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -6216,6 +5818,7 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -6242,15 +5845,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -6260,18 +5854,16 @@ } }, "node_modules/minimatch": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", - "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10" } }, "node_modules/minimist": { @@ -6279,117 +5871,61 @@ "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": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "ISC", "engines": { "node": ">=8" } }, - "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, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch": { + "node_modules/minizlib": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dev": true, - "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/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "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" + "minipass": "^3.0.0", + "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", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "dependencies": { - "minipass": "^3.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", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "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==", - "dev": true - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "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": { - "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==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -6437,136 +5973,13 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-abi": { - "version": "3.87.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.87.0.tgz", - "integrity": "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==", - "dev": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "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, - "optional": true - }, - "node_modules/node-api-version": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.1.tgz", - "integrity": "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==", - "dev": true, - "dependencies": { - "semver": "^7.3.5" - } - }, - "node_modules/node-api-version/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", - "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", - "dev": true, - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^12.13 || ^14.13 || >=16" - } - }, - "node_modules/node-gyp/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-gyp/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "dev": true, + "license": "MIT", + "optional": true }, "node_modules/node-releases": { "version": "2.0.27", @@ -6574,21 +5987,6 @@ "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true }, - "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, - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -6609,22 +6007,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -6659,21 +6041,6 @@ "wrappy": "1" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "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", @@ -6691,29 +6058,6 @@ "node": ">= 0.8.0" } }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -6752,26 +6096,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true + "dev": true, + "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { "version": "1.0.1", @@ -6799,6 +6129,7 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6822,6 +6153,7 @@ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -6837,30 +6169,8 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/pe-library": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-0.4.1.tgz", - "integrity": "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==", "dev": true, - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jet2jet" - } + "license": "ISC" }, "node_modules/pend": { "version": "1.2.0", @@ -6908,6 +6218,7 @@ "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", "dev": true, + "license": "MIT", "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", @@ -7092,6 +6403,7 @@ "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", "peer": true }, "node_modules/progress": { @@ -7102,17 +6414,12 @@ "node": ">=0.4.0" } }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true - }, "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "dev": true, + "license": "MIT", "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -7279,18 +6586,6 @@ } } }, - "node_modules/read-binary-file-arch": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", - "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "bin": { - "read-binary-file-arch": "cli.js" - } - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -7300,11 +6595,31 @@ "pify": "^2.3.0" } }, + "node_modules/read-config-file": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.3.2.tgz", + "integrity": "sha512-M80lpCjnE6Wt6zb98DoW8WHR09nzMSpu8XHtPkiTHrJ5Az9CybfeQhTJ8D7saeBHpGhLPIVyA8lcL6ZmdKwY6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "config-file-ts": "^0.2.4", + "dotenv": "^9.0.2", + "dotenv-expand": "^5.1.0", + "js-yaml": "^4.1.0", + "json5": "^2.2.0", + "lazy-val": "^1.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -7319,41 +6634,12 @@ "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", "dev": true, + "license": "Apache-2.0", "peer": true, "dependencies": { "minimatch": "^5.1.0" } }, - "node_modules/readdir-glob/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "peer": true - }, - "node_modules/readdir-glob/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, - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.7.tgz", - "integrity": "sha512-FjiwU9HaHW6YB3H4a1sFudnv93lvydNjz2lmyUXR6IwKhGI+bgL3SOZrBGn6kvvX2pJvhEkGSGjyTHN47O4rqA==", - "dev": true, - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -7371,6 +6657,7 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7383,23 +6670,6 @@ "node": ">=0.10.0" } }, - "node_modules/resedit": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/resedit/-/resedit-1.7.2.tgz", - "integrity": "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==", - "dev": true, - "dependencies": { - "pe-library": "^0.4.1" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jet2jet" - } - }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", @@ -7445,24 +6715,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -7477,22 +6735,6 @@ "node": ">=0.10.0" } }, - "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, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/roarr": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", @@ -7595,28 +6837,32 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT", + "peer": true }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/sanitize-filename": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", - "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.4.tgz", + "integrity": "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==", "dev": true, + "license": "WTFPL OR ISC", "dependencies": { "truncate-utf8-bytes": "^1.0.0" } }, "node_modules/sax": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", - "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", - "dev": true, + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", "engines": { "node": ">=11.0.0" } @@ -7658,12 +6904,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -7684,10 +6924,17 @@ } }, "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/simple-update-notifier": { "version": "2.0.0", @@ -7718,6 +6965,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "ansi-styles": "^4.0.0", @@ -7733,56 +6981,19 @@ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true, + "license": "MIT", + "optional": true, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" } }, - "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", - "dev": true, - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "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, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/socks-proxy-agent/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, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -7801,6 +7012,7 @@ "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" @@ -7812,23 +7024,12 @@ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", "optional": true }, - "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, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/stat-mode": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -7861,6 +7062,8 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -7870,6 +7073,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", @@ -7885,6 +7089,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", @@ -7899,6 +7104,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" }, @@ -7912,6 +7118,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" }, @@ -8062,6 +7269,7 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "bl": "^4.0.3", @@ -8114,6 +7322,7 @@ "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", "dev": true, + "license": "MIT", "dependencies": { "async-exit-hook": "^2.0.1", "fs-extra": "^10.0.0" @@ -8124,6 +7333,7 @@ "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", @@ -8138,6 +7348,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -8150,6 +7361,7 @@ "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" } @@ -8210,6 +7422,12 @@ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==" }, + "node_modules/tiny-typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", + "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==", + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -8260,6 +7478,7 @@ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.14" } @@ -8269,6 +7488,7 @@ "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", "dev": true, + "license": "MIT", "dependencies": { "tmp": "^0.2.0" } @@ -8317,6 +7537,7 @@ "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", "dev": true, + "license": "WTFPL", "dependencies": { "utf8-byte-length": "^1.0.1" } @@ -8404,30 +7625,6 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" }, - "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, - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.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==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -8487,7 +7684,8 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", - "dev": true + "dev": true, + "license": "(WTFPL OR MIT)" }, "node_modules/util-deprecate": { "version": "1.0.2", @@ -8508,6 +7706,7 @@ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "assert-plus": "^1.0.0", @@ -8577,15 +7776,6 @@ } } }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "dependencies": { - "defaults": "^1.0.3" - } - }, "node_modules/webgl-constants": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", @@ -8610,15 +7800,6 @@ "node": ">= 8" } }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -8633,6 +7814,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -8651,6 +7833,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -8673,6 +7856,7 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0" } @@ -8682,6 +7866,7 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -8697,6 +7882,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -8715,6 +7901,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } @@ -8745,6 +7932,7 @@ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "archiver-utils": "^3.0.4", @@ -8760,6 +7948,7 @@ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "glob": "^7.2.3", diff --git a/package.json b/package.json index 27de181..2695367 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "modly", - "version": "0.1.3", + "version": "0.2.0", "description": "Local AI-powered 3D mesh generation from images", "main": "./out/main/index.js", "author": "Modly", @@ -18,6 +18,7 @@ "@react-three/drei": "^9.120.0", "@react-three/fiber": "^8.17.10", "axios": "^1.7.9", + "electron-updater": "^6.8.3", "react": "^18.3.1", "react-dom": "^18.3.1", "tar": "^7.5.9", @@ -34,7 +35,7 @@ "autoprefixer": "^10.4.20", "cross-env": "^10.1.0", "electron": "^33.3.0", - "electron-builder": "^25.1.8", + "electron-builder": "^24.13.3", "electron-vite": "^2.3.0", "eslint": "^9.17.0", "postcss": "^8.4.49", @@ -62,6 +63,11 @@ ] } ], + "publish": { + "provider": "github", + "owner": "lightningpixel", + "repo": "modly" + }, "nsis": { "oneClick": false, "allowToChangeInstallationDirectory": true @@ -73,10 +79,6 @@ { "from": "resources/python-embed", "to": "python-embed" - }, - { - "from": "resources/get-pip.py", - "to": "get-pip.py" } ] }, @@ -86,7 +88,13 @@ }, "linux": { "target": "AppImage", - "icon": "resources/icons/icon.png" + "icon": "resources/icons/icon.png", + "extraResources": [ + { + "from": "resources/python-embed", + "to": "python-embed" + } + ] } } } diff --git a/scripts/download-python-embed.js b/scripts/download-python-embed.js index 68f10df..25cbd01 100644 --- a/scripts/download-python-embed.js +++ b/scripts/download-python-embed.js @@ -7,34 +7,32 @@ const { execSync } = require('child_process') const RESOURCES_DIR = path.join(__dirname, '..', 'resources') const EMBED_DIR = path.join(RESOURCES_DIR, 'python-embed') -// ── Windows: official embeddable package ───────────────────────────────────── -const WIN_PYTHON_VERSION = '3.11.9' -const WIN_ZIP_URL = `https://www.python.org/ftp/python/${WIN_PYTHON_VERSION}/python-${WIN_PYTHON_VERSION}-embed-amd64.zip` -const WIN_GET_PIP_URL = 'https://bootstrap.pypa.io/get-pip.py' - -// ── Linux / macOS: python-build-standalone ─────────────────────────────────── -const PBS_PYTHON_VERSION = '3.11.9' +// python-build-standalone provides a full Python installation (includes venv + pip) +// Used for ALL platforms — consistent behavior, no stripped-down embed issues. +const PBS_VERSION = '3.11.9' const PBS_RELEASE = '20240726' function getPbsUrl() { const arch = process.arch === 'arm64' ? 'aarch64' : 'x86_64' - const triple = process.platform === 'darwin' - ? `${arch}-apple-darwin` - : `${arch}-unknown-linux-gnu` + const triple = process.platform === 'win32' + ? `${arch}-pc-windows-msvc` + : process.platform === 'darwin' + ? `${arch}-apple-darwin` + : `${arch}-unknown-linux-gnu` return ( `https://github.com/indygreg/python-build-standalone/releases/download/` + - `${PBS_RELEASE}/cpython-${PBS_PYTHON_VERSION}+${PBS_RELEASE}-${triple}-install_only.tar.gz` + `${PBS_RELEASE}/cpython-${PBS_VERSION}+${PBS_RELEASE}-${triple}-install_only.tar.gz` ) } -// ── Shared helpers ──────────────────────────────────────────────────────────── +// ── Helpers ─────────────────────────────────────────────────────────────────── function download(url, dest) { return new Promise((resolve, reject) => { console.log(`Downloading ${url} → ${dest}`) const file = fs.createWriteStream(dest) const request = (u) => { - https.get(u, (res) => { + https.get(u, { headers: { 'User-Agent': 'modly-build' } }, (res) => { if (res.statusCode === 301 || res.statusCode === 302) { request(res.headers.location) return @@ -64,23 +62,11 @@ function download(url, dest) { }) } -// ── Platform-specific extraction ────────────────────────────────────────────── - -function extractZip(zipPath, destDir) { - console.log(`Extracting ${zipPath} → ${destDir}`) - fs.mkdirSync(destDir, { recursive: true }) - execSync( - `powershell -NoProfile -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${destDir}' -Force"`, - { stdio: 'inherit' } - ) -} - function extractTar(tarPath, destDir) { console.log(`Extracting ${tarPath} → ${destDir}`) fs.mkdirSync(destDir, { recursive: true }) // --strip-components=1 removes the top-level "python/" directory from the archive execSync(`tar -xzf "${tarPath}" --strip-components=1 -C "${destDir}"`, { stdio: 'inherit' }) - // On macOS, remove quarantine attribute so Gatekeeper doesn't block execution if (process.platform === 'darwin') { try { execSync(`xattr -cr "${destDir}"`) } catch {} } @@ -91,49 +77,21 @@ function extractTar(tarPath, destDir) { async function main() { fs.mkdirSync(RESOURCES_DIR, { recursive: true }) - if (process.platform === 'win32') { - const pythonExe = path.join(EMBED_DIR, 'python.exe') - const getPipDest = path.join(RESOURCES_DIR, 'get-pip.py') - const zipTmp = path.join(RESOURCES_DIR, 'python-embed.zip') - - if (fs.existsSync(pythonExe) && fs.existsSync(getPipDest)) { - console.log('python-embed (Windows) already present, skipping.') - return - } - - if (!fs.existsSync(pythonExe)) { - await download(WIN_ZIP_URL, zipTmp) - extractZip(zipTmp, EMBED_DIR) - fs.unlinkSync(zipTmp) - console.log('Python embeddable extracted.') - } else { - console.log('python.exe already present, skipping ZIP download.') - } - - if (!fs.existsSync(getPipDest)) { - await download(WIN_GET_PIP_URL, getPipDest) - console.log('get-pip.py downloaded.') - } else { - console.log('get-pip.py already present.') - } - } else { - // Linux / macOS: python-build-standalone (already includes pip) - const pythonExe = path.join(EMBED_DIR, 'bin', 'python3') - - if (fs.existsSync(pythonExe)) { - console.log('python-embed (Unix) already present, skipping.') - return - } + const pythonExe = process.platform === 'win32' + ? path.join(EMBED_DIR, 'python.exe') + : path.join(EMBED_DIR, 'bin', 'python3') - const tarUrl = getPbsUrl() - const tarTmp = path.join(RESOURCES_DIR, 'python-embed.tar.gz') - await download(tarUrl, tarTmp) - extractTar(tarTmp, EMBED_DIR) - fs.unlinkSync(tarTmp) - console.log('Python standalone extracted.') + if (fs.existsSync(pythonExe)) { + console.log('python-embed already present, skipping.') + return } - console.log('Done. Resources ready.') + const tarUrl = getPbsUrl() + const tarTmp = path.join(RESOURCES_DIR, 'python-embed.tar.gz') + await download(tarUrl, tarTmp) + extractTar(tarTmp, EMBED_DIR) + fs.unlinkSync(tarTmp) + console.log('Done. Python standalone extracted.') } main().catch((err) => { diff --git a/src/App.tsx b/src/App.tsx index ddd5e0f..e115217 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,24 +3,27 @@ import { useAppStore } from '@shared/stores/appStore' import FirstRunSetup from '@areas/setup/FirstRunSetup' import MainLayout from '@shared/components/layout/MainLayout' import { UpdateModal } from '@shared/components/ui/UpdateModal' - -function compareSemver(a: string, b: string): number { - const pa = a.replace(/^v/, '').split('.').map(Number) - const pb = b.replace(/^v/, '').split('.').map(Number) - for (let i = 0; i < 3; i++) { - if ((pa[i] ?? 0) > (pb[i] ?? 0)) return 1 - if ((pa[i] ?? 0) < (pb[i] ?? 0)) return -1 - } - return 0 -} +import { ErrorModal } from '@shared/components/ui/ErrorModal' export default function App(): JSX.Element { - const { checkSetup, setupStatus, initApp, backendStatus } = useAppStore() + const { checkSetup, setupStatus, initApp, backendStatus, showError, setPatchUpdateReady } = useAppStore() const [updateVersion, setUpdateVersion] = useState(null) const [currentVersion, setCurrentVersion] = useState('') useEffect(() => { checkSetup() + window.electron.app.onError((message) => showError(message)) + window.electron.updater.onPatchReady(() => { + setPatchUpdateReady(true) + }) + window.electron.updater.onMajorMinorAvailable(({ version }) => { + setUpdateVersion(`v${version}`) + }) + return () => { + window.electron.app.offError() + window.electron.updater.offPatchReady() + window.electron.updater.offMajorMinorAvailable() + } }, []) useEffect(() => { @@ -31,13 +34,7 @@ export default function App(): JSX.Element { if (backendStatus !== 'ready') return window.electron.app.info().then(({ version }) => { setCurrentVersion(version) - fetch('https://api.github.com/repos/lightningpixel/modly/releases/latest') - .then((r) => r.json()) - .then((data) => { - const latest = data?.tag_name as string | undefined - if (latest && compareSemver(latest, version) > 0) setUpdateVersion(latest) - }) - .catch(() => {}) + window.electron.updater.check() }) }, [backendStatus]) @@ -51,7 +48,13 @@ export default function App(): JSX.Element { onDismiss={() => setUpdateVersion(null)} /> )} + + + ) + return ( + <> + + ) - return } diff --git a/src/areas/generate/GeneratePage.tsx b/src/areas/generate/GeneratePage.tsx index cf4cb5b..4aee54c 100644 --- a/src/areas/generate/GeneratePage.tsx +++ b/src/areas/generate/GeneratePage.tsx @@ -1,3 +1,4 @@ +import { useState } from 'react' import { useAppStore } from '@shared/stores/appStore' import { useGeneration } from '@shared/hooks/useGeneration' import ImageUpload from './components/ImageUpload' @@ -8,9 +9,21 @@ import Viewer3D from './components/Viewer3D' export default function GeneratePage(): JSX.Element { const selectedImagePath = useAppStore((s) => s.selectedImagePath) - const { currentJob, startGeneration } = useGeneration() + const modelId = useAppStore((s) => s.generationOptions.modelId) + const { currentJob, startGeneration, cancelGeneration } = useGeneration() const isGenerating = currentJob?.status === 'uploading' || currentJob?.status === 'generating' + const [unloadStatus, setUnloadStatus] = useState<'idle' | 'done'>('idle') + + const canGenerate = !!selectedImagePath && !!modelId && !isGenerating + const disabledReason = !selectedImagePath ? 'Select an image first' : !modelId ? 'No model selected — install one in the Models tab' : undefined + + async function handleUnloadAll() { + await window.electron.model.unloadAll() + setUnloadStatus('done') + setTimeout(() => setUnloadStatus('idle'), 2000) + } + return ( <>
@@ -20,15 +33,25 @@ export default function GeneratePage(): JSX.Element {
- {/* Sticky bottom: Generate button */} + {/* Sticky bottom: Generate / Stop button */}
- + {isGenerating ? ( + + ) : ( + + )}
@@ -36,6 +59,19 @@ export default function GeneratePage(): JSX.Element { + + {/* Free memory button — top-left overlay */} + ) diff --git a/src/areas/generate/components/GenerationOptions.tsx b/src/areas/generate/components/GenerationOptions.tsx index 0cf0f18..964b7ec 100644 --- a/src/areas/generate/components/GenerationOptions.tsx +++ b/src/areas/generate/components/GenerationOptions.tsx @@ -167,7 +167,9 @@ export default function GenerationOptions(): JSX.Element { window.electron.model.listDownloaded() .then((list) => { setModels(list) - if (list.length > 0 && (!generationOptions.modelId || !list.find((m) => m.id === generationOptions.modelId))) { + if (list.length === 0) { + setGenerationOptions({ modelId: '' }) + } else if (!generationOptions.modelId || !list.find((m) => m.id === generationOptions.modelId)) { setGenerationOptions({ modelId: list[0].id }) } }) diff --git a/src/areas/generate/components/ImageUpload.tsx b/src/areas/generate/components/ImageUpload.tsx index b10725d..f5284f7 100644 --- a/src/areas/generate/components/ImageUpload.tsx +++ b/src/areas/generate/components/ImageUpload.tsx @@ -66,11 +66,29 @@ export default function ImageUpload(): JSX.Element { `} > {selectedImagePreviewUrl ? ( - Input + <> + Input + {!isGenerating && ( + + )} + ) : (
diff --git a/src/areas/generate/components/Viewer3D.tsx b/src/areas/generate/components/Viewer3D.tsx index 12d6f41..2054903 100644 --- a/src/areas/generate/components/Viewer3D.tsx +++ b/src/areas/generate/components/Viewer3D.tsx @@ -1,4 +1,5 @@ -import { Suspense, useEffect, useRef, useState } from 'react' +import { Component, Suspense, useEffect, useRef, useState } from 'react' +import type { ReactNode, ErrorInfo } from 'react' import { Canvas, useThree } from '@react-three/fiber' import { OrbitControls, useGLTF } from '@react-three/drei' import * as THREE from 'three' @@ -59,6 +60,55 @@ function CanvasCapture({ return null } +// --------------------------------------------------------------------------- +// ModelErrorBoundary — catches useGLTF load failures (e.g. 404) +// --------------------------------------------------------------------------- + +interface ErrorBoundaryProps { + children: ReactNode + fallback: ReactNode + resetKey?: string | null +} + +interface ErrorBoundaryState { + hasError: boolean +} + +class ModelErrorBoundary extends Component { + state: ErrorBoundaryState = { hasError: false } + + static getDerivedStateFromError(): ErrorBoundaryState { + return { hasError: true } + } + + componentDidCatch(error: Error, info: ErrorInfo): void { + console.warn('[Viewer3D] Failed to load model:', error.message, info.componentStack) + } + + componentDidUpdate(prevProps: ErrorBoundaryProps): void { + if (prevProps.resetKey !== this.props.resetKey && this.state.hasError) { + this.setState({ hasError: false }) + } + } + + render(): ReactNode { + return this.state.hasError ? this.props.fallback : this.props.children + } +} + +function ModelLoadError(): JSX.Element { + return ( +
+ + + + + +

Model file not found

+
+ ) +} + // --------------------------------------------------------------------------- // MeshModel // --------------------------------------------------------------------------- @@ -224,81 +274,83 @@ export default function Viewer3D(): JSX.Element { const canvas = canvasRef.current if (!canvas) return const link = document.createElement('a') - link.download = `localmeshy-${Date.now()}.png` + link.download = `modly-${Date.now()}.png` link.href = canvas.toDataURL('image/png') link.click() } return ( -
- {!modelUrl && } - - - - - - - - {modelUrl && currentJob && ( - - - - - - + }> +
+ {!modelUrl && } + + + + + + + + {modelUrl && currentJob && ( + + + + + + + )} + + + + + {/* Left toolbar — visible only when a model is loaded */} + {modelUrl && ( + setAutoRotate((v) => !v)} + onScreenshot={handleScreenshot} + /> )} - - - - {/* Left toolbar — visible only when a model is loaded */} - {modelUrl && ( - setAutoRotate((v) => !v)} - onScreenshot={handleScreenshot} - /> - )} - - {/* Bottom-left stats overlay */} - {meshStats && ( -
-

- {meshStats.triangles.toLocaleString()} tri • {meshStats.vertices.toLocaleString()} verts -

-
- )} - - {/* Bottom-right hint */} - {modelUrl && ( -
-

Drag to rotate • Scroll to zoom

-
- )} -
+ {/* Bottom-left stats overlay */} + {meshStats && ( +
+

+ {meshStats.triangles.toLocaleString()} tri • {meshStats.vertices.toLocaleString()} verts +

+
+ )} + + {/* Bottom-right hint */} + {modelUrl && ( +
+

Drag to rotate • Scroll to zoom

+
+ )} +
+ ) } diff --git a/src/areas/generate/components/WorkspacePanel.tsx b/src/areas/generate/components/WorkspacePanel.tsx index 0e8d5c6..211127a 100644 --- a/src/areas/generate/components/WorkspacePanel.tsx +++ b/src/areas/generate/components/WorkspacePanel.tsx @@ -4,16 +4,19 @@ import { useCollectionsStore } from '@shared/stores/collectionsStore' import { ConfirmModal } from '@shared/components/ui' import { formatTime, formatDate } from '@shared/utils/format' -function ThumbnailItem({ job, isActive, onClick, onDelete }: { +function ThumbnailItem({ job, isActive, onClick, onDelete, disabled }: { job: GenerationJob isActive: boolean onClick: () => void onDelete: () => void + disabled?: boolean }): JSX.Element { return (
c.id === activeCollectionId) const jobs = activeCollection?.jobs ?? [] const handleDeleteConfirm = () => { - if (pendingDeleteId) removeFromWorkspace(pendingDeleteId) + if (pendingDeleteId) { + if (currentJob?.id === pendingDeleteId) setCurrentJob(null) + removeFromWorkspace(pendingDeleteId) + } setPendingDeleteId(null) } @@ -215,8 +222,9 @@ export default function WorkspacePanel(): JSX.Element { key={job.id} job={job} isActive={currentJob?.id === job.id} - onClick={() => handleJobClick(job)} - onDelete={() => setPendingDeleteId(job.id)} + onClick={() => !isGenerating && handleJobClick(job)} + onDelete={() => !isGenerating && setPendingDeleteId(job.id)} + disabled={isGenerating} /> ))}
diff --git a/src/areas/models/ModelsPage.tsx b/src/areas/models/ModelsPage.tsx index 65d118d..12198ae 100644 --- a/src/areas/models/ModelsPage.tsx +++ b/src/areas/models/ModelsPage.tsx @@ -1,12 +1,13 @@ import { useEffect, useState } from 'react' +import { createPortal } from 'react-dom' import { useAppStore } from '@shared/stores/appStore' import { useNavStore } from '@shared/stores/navStore' import { useExtensionsStore } from '@shared/stores/extensionsStore' +import { useApi } from '@shared/hooks/useApi' import { ConfirmModal } from '@shared/components/ui' import { LocalModel } from './models' import { formatModelName } from './utils' import { ModelCard } from './components/ModelCard' -import { DownloadingCard } from './components/DownloadingCard' import { ExtensionCard, ExtensionVariant } from './components/ExtensionCard' // ─── Page ───────────────────────────────────────────────────────────────────── @@ -27,12 +28,16 @@ export default function ModelsPage(): JSX.Element { const reloadExtensions = useExtensionsStore((s) => s.reload) const clearInstall = useExtensionsStore((s) => s.clearInstallState) + const { getAllModelsStatus } = useApi() + // HF models state - const [models, setModels] = useState([]) - const [downloading, setDownloading] = useState>({}) - const [deleteTarget, setDeleteTarget] = useState(null) - const [deleteError, setDeleteError] = useState(null) - const [uninstallTarget, setUninstallTarget] = useState(null) + const [models, setModels] = useState([]) + const [installedVariantIds, setInstalledVariantIds] = useState([]) + const [downloading, setDownloading] = useState>({}) + const [deleteTarget, setDeleteTarget] = useState(null) + const [deleteError, setDeleteError] = useState(null) + const [uninstallTarget, setUninstallTarget] = useState(null) + const [modelsToDelete, setModelsToDelete] = useState>(new Set()) // GitHub extension install form const [showGHForm, setShowGHForm] = useState(false) @@ -44,13 +49,20 @@ export default function ModelsPage(): JSX.Element { async function refresh() { const list = await window.electron.model.listDownloaded() setModels(list) + try { + const statuses = await getAllModelsStatus() + setInstalledVariantIds(statuses.filter((s) => s.downloaded).map((s) => s.id)) + } catch { + // fallback: derive from directory list + setInstalledVariantIds(list.map((m) => m.id)) + } } useEffect(() => { refresh() loadExtensions() - window.electron.model.onProgress(({ modelId: id, percent }) => { - setDownloading((prev) => ({ ...prev, [id]: percent })) + window.electron.model.onProgress(({ modelId: id, percent, file, fileIndex, totalFiles }) => { + setDownloading((prev) => ({ ...prev, [id]: { percent, file, fileIndex, totalFiles } })) if (percent === 100) { setDownloading((prev) => { const n = { ...prev }; delete n[id]; return n }) refresh() @@ -94,13 +106,25 @@ export default function ModelsPage(): JSX.Element { // ── Uninstall extension ──────────────────────────────────────────────────── + function openUninstallModal(extId: string) { + const ext = extensions.find((e) => e.id === extId) + const installedModels = ext?.models.filter((v) => installedVariantIds.includes(v.id)) ?? [] + setModelsToDelete(new Set(installedModels.map((v) => v.id))) + setUninstallTarget(extId) + } + async function handleUninstallExtension(extId: string) { + // Delete selected models first + for (const modelId of modelsToDelete) { + await window.electron.model.delete(modelId) + } const result = await uninstallExt(extId) setUninstallTarget(null) + setModelsToDelete(new Set()) if (!result.success) { - // Surface the error — for now just log; could show a toast console.error('[extensions:uninstall]', result.error) } + refresh() } // ── Helpers ──────────────────────────────────────────────────────────────── @@ -262,7 +286,7 @@ export default function ModelsPage(): JSX.Element { m.id)} + installedIds={installedVariantIds} downloading={downloading} disabled={isBusy} loadError={ @@ -270,29 +294,20 @@ export default function ModelsPage(): JSX.Element { ext.models.map((v) => loadErrors[v.id]).find(Boolean) } onInstall={(variant: ExtensionVariant) => { - setDownloading((prev) => ({ ...prev, [variant.id]: 0 })) - window.electron.model.download(variant.repoId, variant.id).then((result) => { + setDownloading((prev) => ({ ...prev, [variant.id]: { percent: 0 } })) + window.electron.model.download(variant.repoId, variant.id, variant.hfSkipPrefixes).then((result) => { if (!result.success) { setDownloading((prev) => { const n = { ...prev }; delete n[variant.id]; return n }) } }) }} - onUninstall={(extId) => setUninstallTarget(extId)} + onUninstall={(extId) => openUninstallModal(extId)} /> ))}
)} - {/* In-progress downloads */} - {inProgressIds.length > 0 && ( -
-

Downloading

- {inProgressIds.map((id) => ( - - ))} -
- )} {/* Empty state */} {models.length === 0 && inProgressIds.length === 0 && ( @@ -347,17 +362,89 @@ export default function ModelsPage(): JSX.Element { )} {/* ── Confirm uninstall extension ──────────────────────────────────── */} - {uninstallTarget && ( - handleUninstallExtension(uninstallTarget)} - onCancel={() => setUninstallTarget(null)} - /> - )} + {uninstallTarget && (() => { + const ext = extensions.find((e) => e.id === uninstallTarget) + const installedModels = ext?.models.filter((v) => installedVariantIds.includes(v.id)) ?? [] + + return createPortal( +
{ if (e.target === e.currentTarget) { setUninstallTarget(null); setModelsToDelete(new Set()) } }} + > +
+
+
+
+
+ + + + + + +
+
+

+ Uninstall extension “{ext?.name ?? uninstallTarget}”? +

+

+ The extension folder will be deleted. +

+
+
+ + {installedModels.length > 0 && ( +
+

+ Also delete downloaded model weights: +

+ {installedModels.map((v) => { + const checked = modelsToDelete.has(v.id) + return ( + + ) + })} +
+ )} + +
+ + +
+
+
+
, + document.body + ) + })()}
) } diff --git a/src/areas/models/components/ExtensionCard.tsx b/src/areas/models/components/ExtensionCard.tsx index d7f26c5..2133a88 100644 --- a/src/areas/models/components/ExtensionCard.tsx +++ b/src/areas/models/components/ExtensionCard.tsx @@ -5,7 +5,7 @@ export type { Extension, ExtensionVariant } interface Props { ext: Extension installedIds: string[] - downloading: Record + downloading: Record loadError?: string disabled?: boolean onInstall: (variant: ExtensionVariant) => void @@ -104,8 +104,12 @@ export function ExtensionCard({ ext, installedIds, downloading, loadError, disab
{ext.models.map((variant) => { const installed = installedIds.includes(variant.id) - const dlPercent = downloading[variant.id] - const isDownloading = dlPercent !== undefined + const dlInfo = downloading[variant.id] + const isDownloading = dlInfo !== undefined + const dlPercent = dlInfo?.percent ?? 0 + const dlFile = dlInfo?.file?.split('/').pop() + const dlFileIndex = dlInfo?.fileIndex + const dlTotalFiles = dlInfo?.totalFiles return (
@@ -124,10 +128,14 @@ export function ExtensionCard({ ext, installedIds, downloading, loadError, disab Ready
) : isDownloading ? ( -
+
- Downloading… - {dlPercent}% + + Downloading… {dlFile ?? ''} + + + {dlFileIndex && dlTotalFiles ? `${dlFileIndex}/${dlTotalFiles} · ${dlPercent}%` : `${dlPercent}%`} +
+
+ {/* Open in explorer */} + + {/* Name */} -

+

{formatModelName(model.id)}

diff --git a/src/areas/settings/SettingsPage.tsx b/src/areas/settings/SettingsPage.tsx index 24a973f..7c9952d 100644 --- a/src/areas/settings/SettingsPage.tsx +++ b/src/areas/settings/SettingsPage.tsx @@ -1,8 +1,9 @@ import { useState } from 'react' import { StorageSection } from './components/StorageSection' import { AboutSection } from './components/AboutSection' +import { LogsSection } from './components/LogsSection' -type Section = 'storage' | 'about' +type Section = 'storage' | 'logs' | 'about' const SECTIONS: { id: Section; label: string; icon: JSX.Element }[] = [ { @@ -16,6 +17,19 @@ const SECTIONS: { id: Section; label: string; icon: JSX.Element }[] = [ ) }, + { + id: 'logs', + label: 'Logs', + icon: ( + + + + + + + + ) + }, { id: 'about', label: 'About', @@ -61,6 +75,7 @@ export default function SettingsPage(): JSX.Element {
{section === 'storage' && } + {section === 'logs' && } {section === 'about' && }
diff --git a/src/areas/settings/components/LogsSection.tsx b/src/areas/settings/components/LogsSection.tsx new file mode 100644 index 0000000..22fdbab --- /dev/null +++ b/src/areas/settings/components/LogsSection.tsx @@ -0,0 +1,140 @@ +import { useEffect, useState, useCallback } from 'react' + +const LOG_FILES = [ + { id: 'errors.log', label: 'Errors', description: 'All errors from Electron and Python' }, + { id: 'runtime.log', label: 'Runtime', description: 'FastAPI / Python output' }, + { id: 'modly.log', label: 'App', description: 'General Electron logs' }, +] + +function formatSession(id: string): string { + // id format: 2026-03-20T10-23-45 + try { + const iso = id.replace(/T(\d{2})-(\d{2})-(\d{2})$/, 'T$1:$2:$3') + const d = new Date(iso) + return d.toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' }) + } catch { + return id + } +} + +export function LogsSection(): JSX.Element { + const [sessions, setSessions] = useState([]) + const [activeSession, setActiveSession] = useState(null) // null = current + const [activeFile, setActiveFile] = useState('errors.log') + const [logs, setLogs] = useState>({}) + const [loading, setLoading] = useState(true) + const [copied, setCopied] = useState(false) + + const loadSessions = useCallback(async () => { + const list = await window.electron.log.listSessions() + setSessions(list) + }, []) + + const loadLogs = useCallback(async (session: string | null) => { + setLoading(true) + const result = await window.electron.log.readAll(session ?? undefined) + setLogs(result) + setLoading(false) + }, []) + + useEffect(() => { + loadSessions() + loadLogs(null) + }, [loadSessions, loadLogs]) + + const handleSessionChange = (value: string) => { + const session = value === 'current' ? null : value + setActiveSession(session) + loadLogs(session) + } + + const handleRefresh = () => { + loadSessions() + loadLogs(activeSession) + } + + const content = logs[activeFile] ?? '' + + const handleCopy = () => { + navigator.clipboard.writeText(content).then(() => { + setCopied(true) + setTimeout(() => setCopied(false), 2000) + }) + } + + return ( +
+
+

Logs

+

Application log files — share these when reporting issues.

+
+ + {/* Session selector */} +
+ + +
+ + {/* File tabs */} +
+ {LOG_FILES.map((f) => ( + + ))} + +
+ + +
+
+ + {/* Log content */} + {loading ? ( +
Loading…
+ ) : content ? ( +
+          {content}
+        
+ ) : ( +
+ No entries in {activeFile} +
+ )} +
+ ) +} diff --git a/src/areas/setup/FirstRunSetup.tsx b/src/areas/setup/FirstRunSetup.tsx index 518e36f..720067e 100644 --- a/src/areas/setup/FirstRunSetup.tsx +++ b/src/areas/setup/FirstRunSetup.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import { useAppStore, SetupProgress } from '@shared/stores/appStore' // ─── Logo (shared) ────────────────────────────────────────────────────────── @@ -47,6 +47,59 @@ function CheckingPanel(): JSX.Element { ) } +function ChoosePathPanel({ + defaultPath, + onConfirm, +}: { + defaultPath: string + onConfirm: (path: string) => void +}): JSX.Element { + const [selectedPath, setSelectedPath] = useState(defaultPath || '') + + // Sync if defaultPath arrives after mount (async IPC) + useEffect(() => { + if (defaultPath && !selectedPath) setSelectedPath(defaultPath) + }, [defaultPath]) + + async function handleBrowse() { + const picked = await window.electron.fs.selectDirectory() + if (picked) setSelectedPath(picked) + } + + return ( +
+

Choose a data folder

+

+ Models can be several GB each. Choose a folder on a drive with plenty of free space — + preferably not your system drive (C:). +

+ + {/* Path display */} +
+
+

+ {selectedPath || 'No folder selected'} +

+
+ +
+ + +
+ ) +} + const STEPS = [ { key: 'enabling-site', label: 'Preparing Python' }, { key: 'pip', label: 'Installing pip' }, @@ -135,14 +188,9 @@ function ErrorPanel({ message }: { message: string | null }): JSX.Element { // ─── Main component ───────────────────────────────────────────────────────── export default function FirstRunSetup(): JSX.Element { - const { setupStatus, setupProgress, setupError, runSetup, backendStatus, backendError } = + const { setupStatus, setupProgress, setupError, saveDataDir, defaultDataDir, backendStatus, backendError } = useAppStore() - // Auto-trigger installation when setup is needed - useEffect(() => { - if (setupStatus === 'needed') runSetup() - }, [setupStatus]) - const renderPanel = () => { switch (setupStatus) { case 'idle': @@ -150,6 +198,8 @@ export default function FirstRunSetup(): JSX.Element { return case 'needed': + return + case 'installing': return diff --git a/src/areas/workspace/WorkspacePage.tsx b/src/areas/workspace/WorkspacePage.tsx index be9cd79..fe3caf0 100644 --- a/src/areas/workspace/WorkspacePage.tsx +++ b/src/areas/workspace/WorkspacePage.tsx @@ -19,16 +19,21 @@ export default function WorkspacePage(): JSX.Element { const [addingCol, setAddingCol] = useState(false) const newColRef = useRef(null) + const isGenerating = currentJob?.status === 'uploading' || currentJob?.status === 'generating' const activeCollection = collections.find((c) => c.id === activeCollectionId) const handleJobClick = (job: GenerationJob) => { + if (isGenerating) return // Always restore the original mesh (before any optimization) setCurrentJob({ ...job, outputUrl: job.originalOutputUrl ?? job.outputUrl }) navigate('generate') } const handleDeleteJobConfirm = () => { - if (pendingDeleteId) removeFromWorkspace(pendingDeleteId) + if (pendingDeleteId) { + if (currentJob?.id === pendingDeleteId) setCurrentJob(null) + removeFromWorkspace(pendingDeleteId) + } setPendingDeleteId(null) } @@ -143,6 +148,7 @@ export default function WorkspacePage(): JSX.Element { isActive={currentJob?.id === job.id} onClick={() => handleJobClick(job)} onDelete={() => setPendingDeleteId(job.id)} + disabled={isGenerating} /> ))}
diff --git a/src/areas/workspace/components/WorkspaceCard.tsx b/src/areas/workspace/components/WorkspaceCard.tsx index 9344ce5..8549665 100644 --- a/src/areas/workspace/components/WorkspaceCard.tsx +++ b/src/areas/workspace/components/WorkspaceCard.tsx @@ -6,21 +6,24 @@ interface Props { isActive: boolean onClick: () => void onDelete: () => void + disabled?: boolean } -export function WorkspaceCard({ job, isActive, onClick, onDelete }: Props): JSX.Element { +export function WorkspaceCard({ job, isActive, onClick, onDelete, disabled }: Props): JSX.Element { const modelLabel = job.modelId ? (MODEL_LABEL[job.modelId] ?? job.modelId) : null return (
{/* Thumbnail */}
diff --git a/src/shared/components/layout/TopBar.tsx b/src/shared/components/layout/TopBar.tsx index c8e66ed..411d8d1 100644 --- a/src/shared/components/layout/TopBar.tsx +++ b/src/shared/components/layout/TopBar.tsx @@ -1,4 +1,7 @@ +import { useAppStore } from '@shared/stores/appStore' + export default function TopBar(): JSX.Element { + const { patchUpdateReady } = useAppStore() const handleMinimize = () => window.electron.window.minimize() const handleMaximize = () => window.electron.window.maximize() @@ -29,6 +32,19 @@ export default function TopBar(): JSX.Element { {/* Spacer */}
+ {/* Patch update badge */} + {patchUpdateReady && ( +
+ Update ready + +
+ )} + {/* Window controls */}
+ +
+
+
+ ) +} diff --git a/src/shared/hooks/useApi.ts b/src/shared/hooks/useApi.ts index 9cd335c..4d49311 100644 --- a/src/shared/hooks/useApi.ts +++ b/src/shared/hooks/useApi.ts @@ -11,6 +11,7 @@ export function useApi() { options: GenerationOptions, collection: string = 'Default', imageData?: string, + signal?: AbortSignal, ): Promise<{ jobId: string }> { // Use provided base64 (drag & drop) or read from disk via IPC const base64 = imageData ?? await window.electron.fs.readFileBase64(imagePath) @@ -32,6 +33,7 @@ export function useApi() { formData.append('num_inference_steps', String(options.numInferenceSteps)) const { data } = await client.post<{ job_id: string }>('/generate/from-image', formData, { headers: { 'Content-Type': 'multipart/form-data' }, + signal, }) return { jobId: data.job_id } @@ -58,6 +60,11 @@ export function useApi() { return data } + async function getAllModelsStatus(): Promise<{ id: string; downloaded: boolean }[]> { + const { data } = await client.get('/model/all') + return data + } + async function downloadModel( onProgress?: (pct: number) => void ): Promise { @@ -95,5 +102,9 @@ export function useApi() { return { url: data.url, faceCount: data.face_count } } - return { generateFromImage, pollJobStatus, getModelStatus, downloadModel, optimizeMesh } + async function cancelJob(jobId: string): Promise { + await client.post(`/generate/cancel/${jobId}`).catch(() => {}) + } + + return { generateFromImage, pollJobStatus, cancelJob, getModelStatus, downloadModel, optimizeMesh } } diff --git a/src/shared/hooks/useGeneration.ts b/src/shared/hooks/useGeneration.ts index e4c5970..7f6c383 100644 --- a/src/shared/hooks/useGeneration.ts +++ b/src/shared/hooks/useGeneration.ts @@ -1,4 +1,4 @@ -import { useCallback } from 'react' +import { useCallback, useRef } from 'react' import { useAppStore } from '@shared/stores/appStore' import { useCollectionsStore } from '@shared/stores/collectionsStore' import { useApi } from './useApi' @@ -7,10 +7,14 @@ export function useGeneration() { const { currentJob, setCurrentJob, updateCurrentJob, generationOptions, selectedImageData } = useAppStore() const addToWorkspace = useCollectionsStore((s) => s.addToWorkspace) const activeCollectionId = useCollectionsStore((s) => s.activeCollectionId) - const { generateFromImage, pollJobStatus } = useApi() + const { generateFromImage, pollJobStatus, cancelJob } = useApi() + const cancelledRef = useRef(false) + const abortControllerRef = useRef(null) const startGeneration = useCallback( async (imagePath: string) => { + cancelledRef.current = false + abortControllerRef.current = new AbortController() const job = { id: crypto.randomUUID(), imageFile: imagePath, @@ -23,27 +27,48 @@ export function useGeneration() { setCurrentJob(job) try { - const { jobId } = await generateFromImage(imagePath, generationOptions, activeCollectionId, selectedImageData ?? undefined) + const { jobId } = await generateFromImage(imagePath, generationOptions, activeCollectionId, selectedImageData ?? undefined, abortControllerRef.current.signal) + + if (cancelledRef.current) { + await cancelJob(jobId) + setCurrentJob(null) + return + } updateCurrentJob({ status: 'generating', progress: 0 }) - // Poll until done await pollUntilDone(jobId) } catch (err) { + if (cancelledRef.current) { + setCurrentJob(null) + return + } updateCurrentJob({ status: 'error', error: err instanceof Error ? err.message : String(err) }) } }, - [generateFromImage, pollJobStatus, setCurrentJob, updateCurrentJob, addToWorkspace, activeCollectionId] + [generateFromImage, pollJobStatus, cancelJob, setCurrentJob, updateCurrentJob, addToWorkspace, activeCollectionId] ) const pollUntilDone = async (jobId: string) => { while (true) { await new Promise((r) => setTimeout(r, 1000)) + + if (cancelledRef.current) { + await cancelJob(jobId) + setCurrentJob(null) + break + } + const result = await pollJobStatus(jobId) + if (result.status === 'cancelled') { + setCurrentJob(null) + break + } + if (result.status === 'done') { updateCurrentJob({ status: 'done', progress: 100, outputUrl: result.outputUrl, originalOutputUrl: result.outputUrl }) const finalJob = useAppStore.getState().currentJob @@ -63,7 +88,12 @@ export function useGeneration() { } } + const cancelGeneration = useCallback(() => { + cancelledRef.current = true + abortControllerRef.current?.abort() + }, []) + const reset = useCallback(() => setCurrentJob(null), [setCurrentJob]) - return { currentJob, startGeneration, reset } + return { currentJob, startGeneration, cancelGeneration, reset } } diff --git a/src/shared/stores/appStore.ts b/src/shared/stores/appStore.ts index a8afa94..991cf12 100644 --- a/src/shared/stores/appStore.ts +++ b/src/shared/stores/appStore.ts @@ -81,11 +81,22 @@ interface AppState { toggleWorkspacePanel: () => void // Setup - setupStatus: SetupStatus - setupProgress: SetupProgress | null - setupError: string | null - checkSetup: () => Promise - runSetup: () => Promise + setupStatus: SetupStatus + setupProgress: SetupProgress | null + setupError: string | null + defaultDataDir: string + checkSetup: () => Promise + runSetup: () => Promise + saveDataDir: (baseDir: string) => Promise + + // Patch auto-update + patchUpdateReady: boolean + setPatchUpdateReady: (ready: boolean) => void + + // Error modal + errorModal: string | null + showError: (message: string) => void + hideError: () => void // Actions initApp: () => Promise @@ -104,11 +115,17 @@ export const useAppStore = create()( setupStatus: 'idle', setupProgress: null, setupError: null, + defaultDataDir: '', checkSetup: async () => { set({ setupStatus: 'checking' }) - const { needed } = await window.electron.setup.check() - set({ setupStatus: needed ? 'needed' : 'done' }) + const { needed, defaultDataDir } = await window.electron.setup.check() + set({ setupStatus: needed ? 'needed' : 'done', defaultDataDir }) + }, + + saveDataDir: async (baseDir: string) => { + await window.electron.setup.saveDataDir(baseDir) + get().runSetup() }, runSetup: async () => { @@ -132,6 +149,13 @@ export const useAppStore = create()( window.electron.setup.run() }, + patchUpdateReady: false, + setPatchUpdateReady: (ready) => set({ patchUpdateReady: ready }), + + errorModal: null, + showError: (message) => set({ errorModal: message }), + hideError: () => set({ errorModal: null }), + currentJob: null, selectedImagePath: null, setSelectedImagePath: (path) => set({ selectedImagePath: path }), @@ -149,8 +173,10 @@ export const useAppStore = create()( set({ backendStatus: 'starting', backendError: null }) window.electron.python.offCrashed() - window.electron.python.onCrashed(() => { - set({ backendStatus: 'error', apiUrl: '', backendError: 'FastAPI crashed unexpectedly' }) + window.electron.python.onCrashed(({ code }) => { + const msg = `FastAPI process crashed unexpectedly (exit code: ${code ?? 'unknown'})` + set({ backendStatus: 'error', apiUrl: '', backendError: msg }) + get().showError(msg) }) try { @@ -159,10 +185,9 @@ export const useAppStore = create()( const { apiUrl } = await window.electron.app.info() set({ backendStatus: 'ready', apiUrl }) } catch (err) { - set({ - backendStatus: 'error', - backendError: err instanceof Error ? err.message : String(err), - }) + const msg = err instanceof Error ? err.message : String(err) + set({ backendStatus: 'error', backendError: msg }) + get().showError(msg) } }, diff --git a/src/shared/stores/extensionsStore.ts b/src/shared/stores/extensionsStore.ts index cf472d3..3c99eb9 100644 --- a/src/shared/stores/extensionsStore.ts +++ b/src/shared/stores/extensionsStore.ts @@ -3,10 +3,11 @@ import { create } from 'zustand' // ─── Types ──────────────────────────────────────────────────────────────────── export interface ExtensionVariant { - id: string - name: string - repoId: string - description?: string + id: string + name: string + repoId: string + description?: string + hfSkipPrefixes?: string[] } export interface Extension { diff --git a/src/shared/types/electron.d.ts b/src/shared/types/electron.d.ts index d80163c..708fa63 100644 --- a/src/shared/types/electron.d.ts +++ b/src/shared/types/electron.d.ts @@ -27,22 +27,24 @@ declare global { deleteDirectory: (dirPath: string) => Promise<{ success: boolean; error?: string }> } settings: { - get: () => Promise<{ modelsDir: string; workspaceDir: string }> - set: (patch: { modelsDir?: string; workspaceDir?: string }) => Promise<{ modelsDir: string; workspaceDir: string }> + get: () => Promise<{ modelsDir: string; workspaceDir: string; extensionsDir: string }> + set: (patch: { modelsDir?: string; workspaceDir?: string; extensionsDir?: string }) => Promise<{ modelsDir: string; workspaceDir: string; extensionsDir: string }> } cache: { clear: () => Promise<{ success: boolean; error?: string }> } api: { - updatePaths: (patch: { modelsDir?: string; workspaceDir?: string }) => Promise<{ success: boolean; error?: string }> + updatePaths: (patch: { modelsDir?: string; workspaceDir?: string; extensionsDir?: string }) => Promise<{ success: boolean; error?: string }> } model: { export: (args: { outputUrl: string; format: string }) => Promise<{ success: boolean; error?: string }> listDownloaded: () => Promise<{ id: string; name: string; size_gb: number }[]> isDownloaded: (modelId: string) => Promise - download: (repoId: string, modelId: string) => Promise<{ success: boolean; error?: string }> + download: (repoId: string, modelId: string, skipPrefixes?: string[]) => Promise<{ success: boolean; error?: string }> delete: (modelId: string) => Promise<{ success: boolean; error?: string }> - onProgress: (cb: (data: { modelId: string; percent: number }) => void) => void + unloadAll: () => Promise<{ success: boolean; error?: string }> + showInFolder: (modelId: string) => Promise + onProgress: (cb: (data: { modelId: string; percent: number; file?: string; fileIndex?: number; totalFiles?: number; status?: string }) => void) => void offProgress: () => void } app: { @@ -52,10 +54,14 @@ declare global { modelsDir: string apiUrl: string }> + onError: (cb: (message: string) => void) => void + offError: () => void } log: { error: (message: string) => void getPath: () => Promise + readAll: (session?: string) => Promise> + listSessions: () => Promise } workspace: { listCollections: () => Promise @@ -67,14 +73,23 @@ declare global { deleteJob: (collection: string, filename: string) => Promise } setup: { - check: () => Promise<{ needed: boolean }> - run: () => Promise<{ success: boolean; error?: string }> - onProgress: (cb: (data: { step: string; percent: number; currentPackage?: string }) => void) => void - offProgress: () => void - onComplete: (cb: () => void) => void - offComplete: () => void - onError: (cb: (data: { message: string }) => void) => void - offError: () => void + check: () => Promise<{ needed: boolean; defaultDataDir: string }> + run: () => Promise<{ success: boolean; error?: string }> + saveDataDir: (baseDir: string) => Promise + onProgress: (cb: (data: { step: string; percent: number; currentPackage?: string }) => void) => void + offProgress: () => void + onComplete: (cb: () => void) => void + offComplete: () => void + onError: (cb: (data: { message: string }) => void) => void + offError: () => void + } + updater: { + check: () => Promise<{ success: boolean }> + quitAndInstall: () => Promise + onPatchReady: (cb: (data: { version: string }) => void) => void + offPatchReady: () => void + onMajorMinorAvailable: (cb: (data: { version: string }) => void) => void + offMajorMinorAvailable: () => void } extensions: { list: () => Promise