diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d3f4b04 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +node_modules/ +dist/ +dist-electron/ +release/ +dogfood-output/ +.vite/ +*.log +.DS_Store +.env.local +.env.*.local diff --git a/README.md b/README.md index 99f13ff..83dc97b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,49 @@ -# image-processing +# 正版情趣王 -图片处理 \ No newline at end of file +面向图片交付场景的本地批量处理桌面软件,基于 Electron、Vue 3 和 Sharp 开发。图片只在电脑本地处理,不上传到服务器。 + +## 核心能力 + +- 支持 JPG、JPEG、JPE、JFIF、PNG、WebP、GIF、TIF、TIFF、AVIF、SVG,支持选择文件夹和拖拽导入;动图和多页图片取首帧。 +- 非 JPEG 输入会先转换为高质量 JPEG,透明区域使用白色背景,再执行现有混淆处理。 +- 内置 AI 混淆算法,自动完成图片数据特征混淆与交付兼容处理。 +- 追加数据默认 `1 MB`,可在软件中设置为 `0–100 MB`,设置会保存在本机。 +- 支持生成 `原文件名.file` 和 `原文件名.file.jpg` 两种交付格式。 +- 支持激活码激活、设备绑定、在线授权校验、72 小时离线宽限和软件版本升级检查。 +- 生产接口基地址:`https://apimall.v2.jxxyk.com/api`。 + +## 本地开发 + +```bash +pnpm install +pnpm dev +``` + +## 验证与打包 + +```bash +pnpm test +pnpm run typecheck +pnpm run build +pnpm run dist:win +``` + +Windows 安装包输出到 `release/`,安装程序名称为 `正版情趣王-Setup-<版本号>.exe`。 + +## 后台配套 + +后台项目:`/Users/bing/work/code/jxxyk/jxxyk-v2-mall` + +上线前先执行数据库脚本: + +```text +sql/update/20260826_desktop_image_tool_license.sql +``` + +客户端接口: + +- `POST /api/desktop/activate`:激活并绑定设备。 +- `POST /api/desktop/login`:软件启动/授权校验并记录登录。 +- `POST /api/desktop/version/check`:检查 `正版情趣王` 最新版本。 + +后台管理入口为 `/admin/desktop-license/list`,支持批量生成激活码、启停授权、查看绑定设备及登录记录。软件版本沿用 `/admin/version/list` 管理。 diff --git a/build/icon.png b/build/icon.png new file mode 100644 index 0000000..4facdb6 Binary files /dev/null and b/build/icon.png differ diff --git a/build/icon.svg b/build/icon.svg new file mode 100644 index 0000000..17c490a --- /dev/null +++ b/build/icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/docs/需求/260815.md b/docs/需求/260815.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/需求/参考/郑州情趣王_图片处理逻辑.py b/docs/需求/参考/郑州情趣王_图片处理逻辑.py new file mode 100755 index 0000000..9b94a39 --- /dev/null +++ b/docs/需求/参考/郑州情趣王_图片处理逻辑.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python3 +"""从“郑州情趣王一手科技.exe”提取的 JPEG 图片处理逻辑。 + +处理步骤与原程序一致: +1. 裁掉 JPEG 底部两行并以 quality=95 重新编码; +2. 把 SOF 段中的图片高度改回原始高度; +3. 删除最后一个 JPEG EOI(FF D9)结束标志; +4. 按指定大小追加随机字节,输出为同名 .file 文件。 + +注意:输出是刻意构造的非标准 JPEG,部分看图软件可能拒绝打开。 +""" + +from __future__ import annotations + +import argparse +import random +import sys +from pathlib import Path +from typing import Iterable + +try: + from PIL import Image +except ImportError as exc: + raise SystemExit("缺少 Pillow,请先执行:python3 -m pip install pillow") from exc + + +JPEG_EXTENSIONS = {".jpg", ".jpeg", ".jpe", ".jfif"} +SOF_MARKERS = { + 0xC0, + 0xC1, + 0xC2, + 0xC3, + 0xC5, + 0xC6, + 0xC7, + 0xC9, + 0xCA, + 0xCB, + 0xCD, + 0xCE, + 0xCF, +} + + +def find_and_modify_height(data: bytearray, original_height: int) -> bytearray | None: + """找到第一个 JPEG SOF 段,把高度字段恢复为裁剪前的高度。""" + index = 0 + length = len(data) + + while index < length - 1: + if data[index] != 0xFF: + index += 1 + continue + + marker = data[index + 1] + if marker in SOF_MARKERS: + height_offset = index + 5 + if height_offset + 1 >= length: + return None + data[height_offset] = (original_height >> 8) & 0xFF + data[height_offset + 1] = original_height & 0xFF + return data + + # SOI 和 EOI 标记没有长度字段。 + if marker in (0xD8, 0xD9): + index += 2 + continue + + if index + 3 < length: + segment_length = (data[index + 2] << 8) | data[index + 3] + index += 2 + segment_length + else: + index += 2 + + return None + + +def remove_eoi(data: bytearray) -> tuple[bytearray, bool]: + """从末尾向前查找并删除最后一个 FF D9 结束标志。""" + for index in range(len(data) - 1, 0, -1): + if data[index - 1] == 0xFF and data[index] == 0xD9: + return data[: index - 1] + data[index + 1 :], True + return data, False + + +def process_single_image( + input_file: Path | str, + output_file: Path | str, + junk_size_mb: float = 1.0, +) -> Path: + """按原程序逻辑处理一张图片,并返回输出路径。""" + input_path = Path(input_file) + output_path = Path(output_file) + temp_path = Path(f"{output_path}.tmp") + + if not 0 <= junk_size_mb <= 100: + raise ValueError("junk_size_mb 必须在 0 到 100 之间") + + output_path.parent.mkdir(parents=True, exist_ok=True) + + try: + with Image.open(input_path) as image: + width, height = image.size + if height <= 2: + raise ValueError(f"图片高度不足 3 行:{input_path}") + + cropped_image = image.crop((0, 0, width, height - 2)) + try: + cropped_image.save(temp_path, "JPEG", quality=95) + finally: + cropped_image.close() + + image_data = bytearray(temp_path.read_bytes()) + modified_data = find_and_modify_height(image_data, height) or image_data + modified_data, _ = remove_eoi(modified_data) + + junk_size_bytes = int(junk_size_mb * 1024 * 1024) + if junk_size_bytes > 0: + # 保留原程序的逐字节伪随机生成方式。 + modified_data += bytearray( + random.getrandbits(8) for _ in range(junk_size_bytes) + ) + + output_path.write_bytes(modified_data) + return output_path + finally: + if temp_path.exists(): + temp_path.unlink() + + +def collect_images(paths: Iterable[Path]) -> list[Path]: + """收集输入文件,并按原程序支持的扩展名递归扫描目录。""" + images: list[Path] = [] + for path in paths: + if path.is_file() and path.suffix.lower() in JPEG_EXTENSIONS: + images.append(path) + elif path.is_dir(): + images.extend( + candidate + for candidate in path.rglob("*") + if candidate.is_file() + and candidate.suffix.lower() in JPEG_EXTENSIONS + ) + else: + print(f"跳过无效路径或非 JPEG 文件:{path}", file=sys.stderr) + return images + + +def build_output_path(input_path: Path, output_dir: Path | None) -> Path: + """原程序使用图片主文件名加 .file 作为输出名。""" + directory = output_dir if output_dir is not None else input_path.parent + return directory / f"{input_path.stem}.file" + + +def main() -> int: + parser = argparse.ArgumentParser( + description="裁掉 JPEG 底部两行、伪造原高度、删除 EOI 并追加随机数据。" + ) + parser.add_argument("inputs", nargs="+", type=Path, help="JPEG 文件或目录") + parser.add_argument("-o", "--output-dir", type=Path, help="统一输出目录") + parser.add_argument( + "--junk-mb", + type=float, + default=1.0, + help="每张图片追加的随机数据大小,范围 0–100 MB,默认 1 MB", + ) + args = parser.parse_args() + + if not 0 <= args.junk_mb <= 100: + parser.error("--junk-mb 必须在 0 到 100 之间") + + images = collect_images(args.inputs) + if not images: + print("没有找到可处理的 JPEG 图片。", file=sys.stderr) + return 1 + + succeeded = 0 + for index, input_path in enumerate(images, start=1): + output_path = build_output_path(input_path, args.output_dir) + try: + process_single_image(input_path, output_path, args.junk_mb) + succeeded += 1 + print(f"[{index}/{len(images)}] 完成:{input_path} -> {output_path}") + except Exception as exc: + print(f"[{index}/{len(images)}] 失败:{input_path} - {exc}", file=sys.stderr) + + print(f"处理完成:总计 {len(images)},成功 {succeeded},失败 {len(images) - succeeded}") + return 0 if succeeded == len(images) else 2 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/docs/需求/参考/郑州情趣王一手科技.exe b/docs/需求/参考/郑州情趣王一手科技.exe new file mode 100644 index 0000000..95b5ed5 Binary files /dev/null and b/docs/需求/参考/郑州情趣王一手科技.exe differ diff --git a/electron/main/image-processor.spec.ts b/electron/main/image-processor.spec.ts new file mode 100644 index 0000000..c071d3b --- /dev/null +++ b/electron/main/image-processor.spec.ts @@ -0,0 +1,106 @@ +import { promises as fs } from 'node:fs' +import os from 'node:os' +import path from 'node:path' +import sharp from 'sharp' +import { afterEach, beforeEach, describe, expect, it } from 'vitest' +import type { ProcessOptions } from '../../src/shared/types' +import { + ImageProcessor, + processSingleImage, + readSofHeight, +} from './image-processor' + +describe('image processing algorithm', () => { + let temporaryDirectory: string + let inputPath: string + + beforeEach(async () => { + temporaryDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'genuine-qingquwang-')) + inputPath = path.join(temporaryDirectory, 'sample.jpg') + await sharp({ + create: { + width: 18, + height: 12, + channels: 3, + background: { r: 23, g: 105, b: 224 }, + }, + }).jpeg({ quality: 90 }).toFile(inputPath) + }) + + afterEach(async () => { + await fs.rm(temporaryDirectory, { recursive: true, force: true }) + }) + + it('writes a .file without EOI while restoring original SOF height', async () => { + const outputPath = await processSingleImage(inputPath, options('file', 0)) + const output = await fs.readFile(outputPath) + + expect(outputPath).toBe(path.join(temporaryDirectory, 'sample.file')) + expect(readSofHeight(output)).toBe(12) + expect(output.subarray(-2).equals(Buffer.from([0xff, 0xd9]))).toBe(false) + }) + + it('supports .file.jpg and appends the configured random byte count', async () => { + const baselinePath = await processSingleImage(inputPath, options('file', 0)) + const baselineSize = (await fs.stat(baselinePath)).size + const outputPath = await processSingleImage(inputPath, options('file-jpg', 0.01)) + const outputSize = (await fs.stat(outputPath)).size + + expect(outputPath).toBe(path.join(temporaryDirectory, 'sample.file.jpg')) + expect(outputSize - baselineSize).toBe(Math.floor(0.01 * 1024 * 1024)) + }) + + it('discovers and converts supported non-JPEG inputs into JPEG delivery files', async () => { + const source = sharp({ + create: { + width: 18, + height: 12, + channels: 4, + background: { r: 23, g: 105, b: 224, alpha: 0.5 }, + }, + }) + const inputs = [ + path.join(temporaryDirectory, 'sample.png'), + path.join(temporaryDirectory, 'sample.webp'), + path.join(temporaryDirectory, 'sample.gif'), + path.join(temporaryDirectory, 'sample.tiff'), + path.join(temporaryDirectory, 'sample.avif'), + ] + await Promise.all([ + source.clone().png().toFile(inputs[0]), + source.clone().webp().toFile(inputs[1]), + source.clone().gif().toFile(inputs[2]), + source.clone().tiff().toFile(inputs[3]), + source.clone().avif().toFile(inputs[4]), + fs.writeFile(path.join(temporaryDirectory, 'sample.svg'), ''), + fs.writeFile(path.join(temporaryDirectory, 'ignored.bmp'), 'not-supported'), + ]) + + const processor = new ImageProcessor() + const inspected = await processor.inspect([temporaryDirectory]) + const inspectedNames = inspected.map((item) => item.name) + expect(inspectedNames).toEqual([ + 'sample.avif', + 'sample.gif', + 'sample.jpg', + 'sample.png', + 'sample.svg', + 'sample.tiff', + 'sample.webp', + ]) + + for (const input of [...inputs, path.join(temporaryDirectory, 'sample.svg')]) { + const outputPath = await processSingleImage(input, options('file', 0)) + expect(readSofHeight(await fs.readFile(outputPath))).toBe(12) + } + }) + + function options(outputFormat: 'file' | 'file-jpg', junkSizeMb: number): ProcessOptions { + return { + paths: [inputPath], + useSourceDirectory: true, + outputFormat, + junkSizeMb, + } + } +}) diff --git a/electron/main/image-processor.ts b/electron/main/image-processor.ts new file mode 100644 index 0000000..b6d39c6 --- /dev/null +++ b/electron/main/image-processor.ts @@ -0,0 +1,294 @@ +import { createHash, randomBytes } from 'node:crypto' +import { promises as fs } from 'node:fs' +import path from 'node:path' +import sharp from 'sharp' +import type { + ImageFileItem, + ProcessOptions, + ProcessProgress, + ProcessSummary, +} from '../../src/shared/types' + +export const IMAGE_INPUT_EXTENSIONS = [ + 'jpg', 'jpeg', 'jpe', 'jfif', + 'png', 'webp', 'gif', 'tif', 'tiff', 'avif', 'svg', +] + +const IMAGE_EXTENSIONS = new Set(IMAGE_INPUT_EXTENSIONS.map((extension) => `.${extension}`)) +const SOF_MARKERS = new Set([ + 0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, + 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf, +]) + +export class ImageProcessor { + private cancelled = false + + cancel(): void { + this.cancelled = true + } + + async inspect(inputPaths: string[]): Promise { + const files = await collectImagePaths(inputPaths) + return Promise.all(files.map(async (filePath) => { + const stat = await fs.stat(filePath) + try { + const metadata = await sharp(filePath).metadata() + return { + id: fileId(filePath), + path: filePath, + name: path.basename(filePath), + size: stat.size, + width: metadata.width ?? null, + height: metadata.height ?? null, + status: 'pending' as const, + } + } catch (error) { + return { + id: fileId(filePath), + path: filePath, + name: path.basename(filePath), + size: stat.size, + width: null, + height: null, + status: 'failed' as const, + error: error instanceof Error ? error.message : '无法读取图片', + } + } + })) + } + + async process( + options: ProcessOptions, + onProgress: (progress: ProcessProgress) => void, + ): Promise { + validateOptions(options) + this.cancelled = false + let completed = 0 + let failed = 0 + + for (let index = 0; index < options.paths.length; index++) { + const inputPath = options.paths[index] + if (this.cancelled) { + break + } + const item = await inspectSingle(inputPath) + item.status = 'processing' + onProgress(progressFor(index, options.paths.length, item, false)) + try { + item.outputPath = await processSingleImage(inputPath, options, () => this.cancelled) + item.status = this.cancelled ? 'cancelled' : 'completed' + if (item.status === 'completed') { + completed += 1 + } + } catch (error) { + item.status = this.cancelled ? 'cancelled' : 'failed' + item.error = error instanceof Error ? error.message : '处理失败' + if (!this.cancelled) { + failed += 1 + } + } + onProgress(progressFor(index + 1, options.paths.length, item, this.cancelled)) + } + + return { + total: options.paths.length, + completed, + failed, + cancelled: this.cancelled, + } + } +} + +export async function processSingleImage( + inputPath: string, + options: ProcessOptions, + isCancelled: () => boolean = () => false, +): Promise { + const metadata = await sharp(inputPath, { page: 0, pages: 1 }).metadata() + if (!metadata.width || !metadata.height || metadata.height <= 2) { + throw new Error('图片尺寸过小,无法执行 AI 混淆处理') + } + + const encoded = await sharp(inputPath, { page: 0, pages: 1 }) + .flatten({ background: '#ffffff' }) + .extract({ left: 0, top: 0, width: metadata.width, height: metadata.height - 2 }) + .jpeg({ quality: 95 }) + .toBuffer() + const heightRestored = restoreSofHeight(encoded, metadata.height) + const withoutEoi = removeLastEoi(heightRestored) + const outputPath = buildOutputPath(inputPath, options) + const temporaryPath = `${outputPath}.${process.pid}.tmp` + + await fs.mkdir(path.dirname(outputPath), { recursive: true }) + try { + await fs.writeFile(temporaryPath, withoutEoi) + let remaining = Math.floor(options.junkSizeMb * 1024 * 1024) + if (remaining > 0) { + const handle = await fs.open(temporaryPath, 'a') + try { + while (remaining > 0) { + if (isCancelled()) { + throw new Error('处理已取消') + } + const chunkSize = Math.min(remaining, 1024 * 1024) + await handle.write(randomBytes(chunkSize)) + remaining -= chunkSize + } + } finally { + await handle.close() + } + } + await fs.rm(outputPath, { force: true }) + await fs.rename(temporaryPath, outputPath) + return outputPath + } finally { + await fs.rm(temporaryPath, { force: true }) + } +} + +export function restoreSofHeight(buffer: Buffer, originalHeight: number): Buffer { + const result = Buffer.from(buffer) + let index = 0 + while (index < result.length - 1) { + if (result[index] !== 0xff) { + index += 1 + continue + } + let markerIndex = index + 1 + while (markerIndex < result.length && result[markerIndex] === 0xff) { + markerIndex += 1 + } + const marker = result[markerIndex] + if (SOF_MARKERS.has(marker)) { + const heightOffset = markerIndex + 4 + if (heightOffset + 1 >= result.length) { + throw new Error('JPEG SOF 高度字段不完整') + } + result[heightOffset] = (originalHeight >> 8) & 0xff + result[heightOffset + 1] = originalHeight & 0xff + return result + } + if (marker === 0xd8 || marker === 0xd9 || (marker >= 0xd0 && marker <= 0xd7)) { + index = markerIndex + 1 + continue + } + if (markerIndex + 2 >= result.length) { + break + } + const segmentLength = result.readUInt16BE(markerIndex + 1) + if (segmentLength < 2) { + break + } + index = markerIndex + 1 + segmentLength + } + throw new Error('未找到 JPEG SOF 图片尺寸段') +} + +export function removeLastEoi(buffer: Buffer): Buffer { + for (let index = buffer.length - 1; index > 0; index--) { + if (buffer[index - 1] === 0xff && buffer[index] === 0xd9) { + return Buffer.concat([buffer.subarray(0, index - 1), buffer.subarray(index + 1)]) + } + } + return buffer +} + +export function readSofHeight(buffer: Buffer): number | null { + let index = 0 + while (index < buffer.length - 7) { + if (buffer[index] === 0xff && SOF_MARKERS.has(buffer[index + 1])) { + return buffer.readUInt16BE(index + 5) + } + index += 1 + } + return null +} + +async function collectImagePaths(inputPaths: string[]): Promise { + const result: string[] = [] + const seen = new Set() + const stack = [...inputPaths] + while (stack.length > 0) { + const candidate = stack.pop() + if (!candidate) continue + let stat + try { + stat = await fs.lstat(candidate) + } catch { + continue + } + if (stat.isSymbolicLink()) continue + if (stat.isDirectory()) { + const entries = await fs.readdir(candidate, { withFileTypes: true }) + for (const entry of entries) { + if (!entry.isSymbolicLink()) { + stack.push(path.join(candidate, entry.name)) + } + } + } else if (stat.isFile() && IMAGE_EXTENSIONS.has(path.extname(candidate).toLowerCase())) { + const absolutePath = path.resolve(candidate) + if (!seen.has(absolutePath)) { + seen.add(absolutePath) + result.push(absolutePath) + } + } + } + return result.sort((left, right) => left.localeCompare(right, 'zh-CN')) +} + +async function inspectSingle(filePath: string): Promise { + const [stat, metadata] = await Promise.all([ + fs.stat(filePath), + sharp(filePath).metadata(), + ]) + return { + id: fileId(filePath), + path: filePath, + name: path.basename(filePath), + size: stat.size, + width: metadata.width ?? null, + height: metadata.height ?? null, + status: 'pending', + } +} + +function buildOutputPath(inputPath: string, options: ProcessOptions): string { + const outputDirectory = options.useSourceDirectory + ? path.dirname(inputPath) + : path.resolve(options.outputDirectory || '') + const basename = path.basename(inputPath, path.extname(inputPath)) + const suffix = options.outputFormat === 'file-jpg' ? '.file.jpg' : '.file' + return path.join(outputDirectory, `${basename}${suffix}`) +} + +function validateOptions(options: ProcessOptions): void { + if (!options.paths.length) { + throw new Error('请先添加需要处理的图片') + } + if (!options.useSourceDirectory && !options.outputDirectory) { + throw new Error('请选择输出目录') + } + if (!Number.isFinite(options.junkSizeMb) + || options.junkSizeMb < 0 || options.junkSizeMb > 100) { + throw new Error('追加数据大小必须在 0 到 100 MB 之间') + } +} + +function fileId(filePath: string): string { + return createHash('sha1').update(filePath).digest('hex') +} + +function progressFor( + current: number, + total: number, + item: ImageFileItem, + cancelled: boolean, +): ProcessProgress { + return { + current, + total, + percent: total === 0 ? 0 : Math.round((current / total) * 100), + item, + cancelled, + } +} diff --git a/electron/main/index.ts b/electron/main/index.ts new file mode 100644 index 0000000..78fd3a6 --- /dev/null +++ b/electron/main/index.ts @@ -0,0 +1,333 @@ +import { + app, + BrowserWindow, + dialog, + ipcMain, + session, + shell, +} from 'electron' +import type { + DownloadItem, + Event as ElectronEvent, + IpcMainInvokeEvent, + WebContents, +} from 'electron' +import { existsSync } from 'node:fs' +import path from 'node:path' +import type { ProcessOptions } from '../../src/shared/types' +import { IMAGE_INPUT_EXTENSIONS, ImageProcessor } from './image-processor' +import { LicenseManager } from './license-manager' + +app.setName('正版情趣王') +app.enableSandbox() + +const singleInstance = app.requestSingleInstanceLock() +if (!singleInstance) { + app.quit() +} + +let mainWindow: BrowserWindow | null = null +const imageProcessor = new ImageProcessor() +const licenseManager = new LicenseManager() +const UPDATE_INSTALLER_EXTENSIONS = new Set(['.exe', '.msi']) + +function createWindow(): void { + const preload = path.join(__dirname, '../preload/index.js') + const windowOptions: Electron.BrowserWindowConstructorOptions = { + width: 1360, + height: 860, + minWidth: 1120, + minHeight: 720, + show: false, + backgroundColor: '#F4F7FB', + title: '正版情趣王', + titleBarStyle: 'hidden', + webPreferences: { + preload, + contextIsolation: true, + nodeIntegration: false, + sandbox: true, + webSecurity: true, + }, + } + if (process.platform !== 'darwin') { + windowOptions.titleBarOverlay = { + color: '#F7F9FC', + symbolColor: '#596273', + height: 48, + } + } + mainWindow = new BrowserWindow(windowOptions) + + mainWindow.webContents.setWindowOpenHandler(() => ({ action: 'deny' })) + mainWindow.webContents.on('will-navigate', (event, targetUrl) => { + if (targetUrl !== mainWindow?.webContents.getURL()) { + event.preventDefault() + } + }) + mainWindow.once('ready-to-show', () => mainWindow?.show()) + + const devServerUrl = process.env.VITE_DEV_SERVER_URL + if (devServerUrl) { + void mainWindow.loadURL(devServerUrl) + } else { + void mainWindow.loadFile(path.join(__dirname, '../../../dist/index.html')) + } +} + +function registerIpcHandlers(): void { + ipcMain.handle('app:info', (event) => { + assertTrustedSender(event) + return licenseManager.getAppInfo() + }) + ipcMain.handle('license:state', (event) => { + assertTrustedSender(event) + return licenseManager.getState() + }) + ipcMain.handle('license:activate', (event, activationCode: unknown) => { + assertTrustedSender(event) + if (typeof activationCode !== 'string' || activationCode.length > 64) { + throw new Error('激活码格式不正确') + } + return licenseManager.activate(activationCode) + }) + ipcMain.handle('license:validate', (event) => { + assertTrustedSender(event) + return licenseManager.validate() + }) + ipcMain.handle('license:clear', (event) => { + assertTrustedSender(event) + return licenseManager.clear() + }) + ipcMain.handle('license:check-version', (event) => { + assertTrustedSender(event) + return licenseManager.checkVersion() + }) + ipcMain.handle('license:download-update', async ( + event, + downloadUrl: unknown, + latestVersion: unknown, + ) => { + assertTrustedSender(event) + const url = validateUpdateUrl(downloadUrl) + const savePath = await downloadUpdateInstaller(event.sender, url, latestVersion) + const choice = await dialog.showMessageBox(mainWindow!, { + type: 'info', + title: '更新已下载', + message: '新版安装包下载完成', + detail: '安装包已保存到:\n' + savePath + '\n\n点击“立即安装”继续升级,安装程序可能会提示关闭当前软件。', + buttons: ['立即安装', '打开文件夹', '稍后安装'], + defaultId: 0, + cancelId: 2, + noLink: true, + }) + if (choice.response === 0) { + const openError = await shell.openPath(savePath) + if (openError) { + throw new Error('无法启动安装程序:' + openError) + } + } else if (choice.response === 1) { + shell.showItemInFolder(savePath) + } + }) + ipcMain.handle('images:select-files', async (event) => { + assertTrustedSender(event) + const result = await dialog.showOpenDialog(mainWindow!, { + title: '选择图片', + properties: ['openFile', 'multiSelections'], + filters: [{ name: '支持的图片', extensions: IMAGE_INPUT_EXTENSIONS }], + }) + return result.canceled ? [] : result.filePaths + }) + ipcMain.handle('images:select-folder', async (event) => { + assertTrustedSender(event) + const result = await dialog.showOpenDialog(mainWindow!, { + title: '选择图片文件夹', + properties: ['openDirectory'], + }) + return result.canceled ? [] : result.filePaths + }) + ipcMain.handle('images:select-output', async (event) => { + assertTrustedSender(event) + const result = await dialog.showOpenDialog(mainWindow!, { + title: '选择输出目录', + properties: ['openDirectory', 'createDirectory'], + }) + return result.canceled ? null : result.filePaths[0] + }) + ipcMain.handle('images:inspect', (event, paths: unknown) => { + assertTrustedSender(event) + return imageProcessor.inspect(validatePaths(paths)) + }) + ipcMain.handle('images:process', (event, options: ProcessOptions) => { + assertTrustedSender(event) + const validated: ProcessOptions = { + ...options, + paths: validatePaths(options?.paths), + } + return imageProcessor.process(validated, (progress) => { + if (!event.sender.isDestroyed()) { + event.sender.send('images:progress', progress) + } + }) + }) + ipcMain.handle('images:cancel', (event) => { + assertTrustedSender(event) + imageProcessor.cancel() + }) + ipcMain.handle('images:reveal', (event, filePath: unknown) => { + assertTrustedSender(event) + if (typeof filePath !== 'string' || !path.isAbsolute(filePath)) { + throw new Error('文件路径无效') + } + shell.showItemInFolder(filePath) + }) +} + +function validateUpdateUrl(value: unknown): URL { + if (typeof value !== 'string') { + throw new Error('下载地址无效') + } + const url = new URL(value) + if (url.protocol !== 'https:') { + throw new Error('安装包必须通过 HTTPS 下载') + } + const extension = path.extname(decodeUrlPathname(url)).toLowerCase() + if (!UPDATE_INSTALLER_EXTENSIONS.has(extension)) { + throw new Error('下载地址不是受支持的 Windows 安装包') + } + return url +} + +function decodeUrlPathname(url: URL): string { + try { + return decodeURIComponent(url.pathname) + } catch { + throw new Error('安装包下载地址格式不正确') + } +} + +function installerFilename(url: URL, latestVersion: unknown): string { + const extension = path.extname(decodeUrlPathname(url)).toLowerCase() + const version = typeof latestVersion === 'string' + ? latestVersion.trim().replace(/^v/i, '').replace(/[^0-9A-Za-z._-]/g, '').slice(0, 32) + : '' + return version + ? '正版情趣王-Setup-' + version + extension + : '正版情趣王-Setup' + extension +} + +function availableDownloadPath(filename: string): string { + const downloadsDirectory = app.getPath('downloads') + const extension = path.extname(filename) + const basename = path.basename(filename, extension) + let candidate = path.join(downloadsDirectory, filename) + for (let index = 2; existsSync(candidate); index += 1) { + candidate = path.join(downloadsDirectory, basename + '-' + index + extension) + } + return candidate +} + +function downloadUpdateInstaller( + sender: WebContents, + url: URL, + latestVersion: unknown, +): Promise { + const savePath = availableDownloadPath(installerFilename(url, latestVersion)) + const browserSession = sender.session + + return new Promise((resolve, reject) => { + let downloadItem: DownloadItem | null = null + let settled = false + + const cleanup = (): void => { + clearTimeout(timeout) + browserSession.removeListener('will-download', handleDownload) + } + const finish = (error?: Error): void => { + if (settled) return + settled = true + cleanup() + if (error) reject(error) + else resolve(savePath) + } + const handleDownload = ( + _event: ElectronEvent, + item: DownloadItem, + source: WebContents, + ): void => { + if (source !== sender) return + downloadItem = item + browserSession.removeListener('will-download', handleDownload) + item.setSavePath(savePath) + item.once('done', (_doneEvent, state) => { + if (state === 'completed') { + finish() + } else { + finish(new Error(state === 'cancelled' ? '安装包下载已取消' : '安装包下载中断,请重试')) + } + }) + } + const timeout = setTimeout(() => { + downloadItem?.cancel() + finish(new Error('安装包下载超时,请检查网络后重试')) + }, 30 * 60 * 1000) + + browserSession.on('will-download', handleDownload) + try { + // 由 Electron 直接下载,避免依赖 Windows 的 HTTPS 默认应用关联。 + sender.downloadURL(url.toString()) + } catch (error) { + finish(error instanceof Error ? error : new Error('无法开始下载安装包')) + } + }) +} + +function assertTrustedSender(event: IpcMainInvokeEvent): void { + const senderUrl = event.senderFrame?.url || '' + if (senderUrl.startsWith('file://')) { + return + } + if (!app.isPackaged && senderUrl.startsWith('http://127.0.0.1:5173')) { + return + } + throw new Error('拒绝来自非可信页面的请求') +} + +function validatePaths(value: unknown): string[] { + if (!Array.isArray(value) || value.length > 10_000) { + throw new Error('文件列表无效') + } + return value.map((item) => { + if (typeof item !== 'string' || !path.isAbsolute(item) || item.length > 4096) { + throw new Error('文件路径无效') + } + return item + }) +} + +if (singleInstance) { + app.whenReady().then(() => { + app.setAppUserModelId('com.jxxyk.genuineqingquwang') + session.defaultSession.setPermissionRequestHandler((_webContents, _permission, callback) => { + callback(false) + }) + registerIpcHandlers() + createWindow() + }) + + app.on('second-instance', () => { + if (mainWindow) { + if (mainWindow.isMinimized()) mainWindow.restore() + mainWindow.focus() + } + }) + + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) + + app.on('window-all-closed', () => { + if (process.platform !== 'darwin') app.quit() + }) +} diff --git a/electron/main/license-manager.ts b/electron/main/license-manager.ts new file mode 100644 index 0000000..d02f29f --- /dev/null +++ b/electron/main/license-manager.ts @@ -0,0 +1,170 @@ +import { app } from 'electron' +import { createHash } from 'node:crypto' +import os from 'node:os' +import { machineIdSync } from 'node-machine-id' +import type { + AppInfo, + LicenseSession, + LicenseViewState, + VersionInfo, +} from '../../src/shared/types' +import { LicenseStore, type StoredLicense } from './license-store' +import { + DesktopServerApi, + type DevicePayload, + ServerApiError, +} from './server-api' + +const OFFLINE_GRACE_MS = 72 * 60 * 60 * 1000 + +export class LicenseManager { + private readonly store = new LicenseStore() + private readonly server = new DesktopServerApi() + + getAppInfo(): AppInfo { + return { + name: '正版情趣王', + version: app.getVersion(), + platform: process.platform, + deviceName: os.hostname(), + } + } + + async getState(): Promise { + const stored = await this.store.load() + if (!stored) { + return { + status: 'unlicensed', + message: '输入激活码后即可开始使用', + offline: false, + } + } + return this.validateStored(stored) + } + + async activate(activationCode: string): Promise { + try { + const session = await this.server.activate(activationCode, this.devicePayload()) + if (!session.token) { + throw new ServerApiError('INVALID_RESPONSE', '授权服务未返回设备凭据') + } + await this.persistSession(session) + return { + status: 'active', + message: '设备已激活', + offline: false, + session, + version: session.version, + } + } catch (error) { + return this.errorState(error) + } + } + + async validate(): Promise { + const stored = await this.store.load() + if (!stored) { + return { + status: 'unlicensed', + message: '当前设备尚未激活', + offline: false, + } + } + return this.validateStored(stored) + } + + async clear(): Promise { + await this.store.clear() + return { + status: 'unlicensed', + message: '本机授权凭据已清除', + offline: false, + } + } + + checkVersion(): Promise { + return this.server.checkVersion(app.getVersion()) + } + + private async validateStored(stored: StoredLicense): Promise { + try { + const session = await this.server.login(stored.token, this.devicePayload()) + session.token = stored.token + await this.persistSession(session) + return { + status: 'active', + message: '授权有效', + offline: false, + session, + version: session.version, + } + } catch (error) { + if (error instanceof ServerApiError && error.code.startsWith('NETWORK_') + && this.canUseOffline(stored)) { + const session: LicenseSession = { + licenseCodeMask: stored.licenseCodeMask, + deviceMask: stored.deviceMask, + expiresAt: stored.expiresAt, + maxDevices: stored.maxDevices, + } + return { + status: 'active', + message: '当前处于离线授权模式,请在 72 小时内联网校验', + offline: true, + session, + } + } + return this.errorState(error) + } + } + + private async persistSession(session: LicenseSession): Promise { + if (!session.token) { + throw new Error('缺少设备授权凭据') + } + await this.store.save({ + token: session.token, + licenseCodeMask: session.licenseCodeMask, + deviceMask: session.deviceMask, + expiresAt: session.expiresAt, + maxDevices: session.maxDevices, + lastVerifiedAt: new Date().toISOString(), + }) + } + + private canUseOffline(stored: StoredLicense): boolean { + const lastVerifiedAt = new Date(stored.lastVerifiedAt).getTime() + const expiresAt = stored.expiresAt ? new Date(stored.expiresAt).getTime() : Number.POSITIVE_INFINITY + return Number.isFinite(lastVerifiedAt) + && Date.now() - lastVerifiedAt <= OFFLINE_GRACE_MS + && Date.now() < expiresAt + } + + private errorState(error: unknown): LicenseViewState { + if (error instanceof ServerApiError) { + return { + status: error.code.startsWith('NETWORK_') ? 'network-error' : 'invalid', + message: error.message, + offline: false, + } + } + return { + status: 'invalid', + message: error instanceof Error ? error.message : '授权校验失败', + offline: false, + } + } + + private devicePayload(): DevicePayload { + const deviceId = createHash('sha256') + .update(`正版情趣王:${machineIdSync()}`) + .digest('hex') + return { + deviceId, + deviceName: os.hostname(), + osName: `${os.type()} ${os.arch()}`, + osVersion: os.release(), + appVersion: app.getVersion(), + } + } +} diff --git a/electron/main/license-store.ts b/electron/main/license-store.ts new file mode 100644 index 0000000..5def37b --- /dev/null +++ b/electron/main/license-store.ts @@ -0,0 +1,70 @@ +import { app, safeStorage } from 'electron' +import { promises as fs } from 'node:fs' +import path from 'node:path' + +export interface StoredLicense { + token: string + licenseCodeMask: string + deviceMask: string + expiresAt?: string + maxDevices: number + lastVerifiedAt: string +} + +interface StoredLicenseFile { + encryptedToken: string + licenseCodeMask: string + deviceMask: string + expiresAt?: string + maxDevices: number + lastVerifiedAt: string +} + +export class LicenseStore { + private get filePath(): string { + return path.join(app.getPath('userData'), 'license.json') + } + + async load(): Promise { + try { + const raw = await fs.readFile(this.filePath, 'utf8') + const stored = JSON.parse(raw) as StoredLicenseFile + const decrypted = await safeStorage.decryptStringAsync( + Buffer.from(stored.encryptedToken, 'base64'), + ) + return { + token: decrypted.result, + licenseCodeMask: stored.licenseCodeMask, + deviceMask: stored.deviceMask, + expiresAt: stored.expiresAt, + maxDevices: stored.maxDevices, + lastVerifiedAt: stored.lastVerifiedAt, + } + } catch { + return null + } + } + + async save(license: StoredLicense): Promise { + if (!(await safeStorage.isAsyncEncryptionAvailable())) { + throw new Error('系统安全凭据存储不可用') + } + const encryptedToken = await safeStorage.encryptStringAsync(license.token) + const stored: StoredLicenseFile = { + encryptedToken: encryptedToken.toString('base64'), + licenseCodeMask: license.licenseCodeMask, + deviceMask: license.deviceMask, + expiresAt: license.expiresAt, + maxDevices: license.maxDevices, + lastVerifiedAt: license.lastVerifiedAt, + } + await fs.mkdir(path.dirname(this.filePath), { recursive: true }) + const temporaryPath = `${this.filePath}.tmp` + await fs.writeFile(temporaryPath, JSON.stringify(stored), { mode: 0o600 }) + await fs.rename(temporaryPath, this.filePath) + } + + async clear(): Promise { + await fs.rm(this.filePath, { force: true }) + } +} diff --git a/electron/main/server-api-headers.spec.ts b/electron/main/server-api-headers.spec.ts new file mode 100644 index 0000000..b8e91cb --- /dev/null +++ b/electron/main/server-api-headers.spec.ts @@ -0,0 +1,15 @@ +import { describe, expect, it } from 'vitest' +import { buildDesktopRequestHeaders } from './server-api-headers' + +describe('desktop server request headers', () => { + it('builds a Fetch-compatible ASCII client header', () => { + const headers = buildDesktopRequestHeaders('1.0.0') + + expect(headers['X-Desktop-Client']).toBe('genuine-qingquwang/1.0.0') + expect(() => new Headers(headers)).not.toThrow() + }) + + it('rejects non-ASCII version labels before making a request', () => { + expect(() => buildDesktopRequestHeaders('版本-1.0.0')).toThrow(/ASCII/) + }) +}) diff --git a/electron/main/server-api-headers.ts b/electron/main/server-api-headers.ts new file mode 100644 index 0000000..99e90cb --- /dev/null +++ b/electron/main/server-api-headers.ts @@ -0,0 +1,15 @@ +const DESKTOP_CLIENT_ID = 'genuine-qingquwang' +const VISIBLE_ASCII = /^[\x20-\x7E]+$/ + +export function buildDesktopRequestHeaders(version: string): Record { + const clientHeader = `${DESKTOP_CLIENT_ID}/${version}` + // Fetch 请求头必须是 ByteString,禁止中文等非 ASCII 字符在发请求前触发异常。 + if (!VISIBLE_ASCII.test(clientHeader)) { + throw new Error('桌面客户端版本标识必须使用 ASCII 字符') + } + return { + Accept: 'application/json', + 'Content-Type': 'application/json', + 'X-Desktop-Client': clientHeader, + } +} diff --git a/electron/main/server-api.ts b/electron/main/server-api.ts new file mode 100644 index 0000000..feaf43b --- /dev/null +++ b/electron/main/server-api.ts @@ -0,0 +1,102 @@ +import { app, net } from 'electron' +import type { + LicenseSession, + VersionInfo, +} from '../../src/shared/types' +import { buildDesktopRequestHeaders } from './server-api-headers' + +interface ApiResult { + code: string + msg: string + data: T +} + +export interface DevicePayload { + deviceId: string + deviceName: string + osName: string + osVersion: string + appVersion: string +} + +export class ServerApiError extends Error { + constructor( + public readonly code: string, + message: string, + ) { + super(message) + this.name = 'ServerApiError' + } +} + +const DEFAULT_API_BASE_URL = 'https://apimall.v2.jxxyk.com/api' + +export class DesktopServerApi { + private readonly baseUrl: string + + constructor(baseUrl = process.env.IMAGE_TOOL_API_BASE_URL || DEFAULT_API_BASE_URL) { + this.baseUrl = this.validateBaseUrl(baseUrl) + } + + activate(activationCode: string, device: DevicePayload): Promise { + return this.post('/desktop/activate', { + activationCode, + ...device, + }) + } + + login(token: string, device: DevicePayload): Promise { + return this.post('/desktop/login', { + token, + ...device, + }) + } + + checkVersion(currentVersion: string): Promise { + return this.post('/desktop/version/check', { + currentVersion, + platform: 'windows', + }) + } + + private async post(pathname: string, body: unknown): Promise { + const controller = new AbortController() + const timeout = setTimeout(() => controller.abort(), 15_000) + try { + const response = await net.fetch(`${this.baseUrl}${pathname}`, { + method: 'POST', + headers: buildDesktopRequestHeaders(app.getVersion()), + body: JSON.stringify(body), + signal: controller.signal, + }) + if (!response.ok) { + throw new ServerApiError(String(response.status), `授权服务暂时不可用(${response.status})`) + } + const result = (await response.json()) as ApiResult + if (result.code !== '0') { + throw new ServerApiError(result.code, result.msg || '授权校验失败') + } + return result.data + } catch (error) { + if (error instanceof ServerApiError) { + throw error + } + if (error instanceof Error && error.name === 'AbortError') { + throw new ServerApiError('NETWORK_TIMEOUT', '连接授权服务超时,请检查网络后重试') + } + throw new ServerApiError('NETWORK_ERROR', '无法连接授权服务,请检查网络后重试') + } finally { + clearTimeout(timeout) + } + } + + private validateBaseUrl(value: string): string { + const url = new URL(value.trim()) + const localDevelopment = url.protocol === 'http:' + && ['127.0.0.1', 'localhost'].includes(url.hostname) + if (url.protocol !== 'https:' && !(localDevelopment && !app.isPackaged)) { + throw new Error('生产授权服务必须使用 HTTPS') + } + return url.toString().replace(/\/$/, '') + } +} diff --git a/electron/preload/index.ts b/electron/preload/index.ts new file mode 100644 index 0000000..2e269a5 --- /dev/null +++ b/electron/preload/index.ts @@ -0,0 +1,36 @@ +import { contextBridge, ipcRenderer, webUtils } from 'electron' +import type { + DesktopBridge, + ProcessProgress, +} from '../../src/shared/types' + +const bridge: DesktopBridge = { + getAppInfo: () => ipcRenderer.invoke('app:info'), + getLicenseState: () => ipcRenderer.invoke('license:state'), + activate: (activationCode) => ipcRenderer.invoke('license:activate', activationCode), + validateLicense: () => ipcRenderer.invoke('license:validate'), + clearLicense: () => ipcRenderer.invoke('license:clear'), + checkVersion: () => ipcRenderer.invoke('license:check-version'), + downloadUpdate: (downloadUrl, latestVersion) => ipcRenderer.invoke( + 'license:download-update', + downloadUrl, + latestVersion, + ), + selectImages: () => ipcRenderer.invoke('images:select-files'), + selectFolder: () => ipcRenderer.invoke('images:select-folder'), + selectOutputDirectory: () => ipcRenderer.invoke('images:select-output'), + pathsForFiles: (files) => files + .map((file) => webUtils.getPathForFile(file)) + .filter(Boolean), + inspectImages: (paths) => ipcRenderer.invoke('images:inspect', paths), + processImages: (options) => ipcRenderer.invoke('images:process', options), + cancelProcessing: () => ipcRenderer.invoke('images:cancel'), + revealItem: (filePath) => ipcRenderer.invoke('images:reveal', filePath), + onProcessProgress: (callback) => { + const listener = (_event: Electron.IpcRendererEvent, progress: ProcessProgress) => callback(progress) + ipcRenderer.on('images:progress', listener) + return () => ipcRenderer.removeListener('images:progress', listener) + }, +} + +contextBridge.exposeInMainWorld('desktop', bridge) diff --git a/index.html b/index.html new file mode 100644 index 0000000..e0319ea --- /dev/null +++ b/index.html @@ -0,0 +1,14 @@ + + + + + + + + 正版情趣王 + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..1dcf1a8 --- /dev/null +++ b/package.json @@ -0,0 +1,83 @@ +{ + "name": "genuine-qingquwang", + "version": "1.0.0", + "private": true, + "author": "星驿科技", + "description": "正版情趣王 JPEG 图片批处理桌面软件", + "main": "dist-electron/electron/main/index.js", + "scripts": { + "dev": "concurrently -k \"vite --host 127.0.0.1 --port 5173\" \"tsc -p tsconfig.electron.json --watch --preserveWatchOutput\" \"wait-on tcp:5173 file:dist-electron/electron/main/index.js && cross-env VITE_DEV_SERVER_URL=http://127.0.0.1:5173 electron .\"", + "build:renderer": "vite build", + "prebuild:electron": "node scripts/clean-electron.cjs", + "build:electron": "tsc -p tsconfig.electron.json", + "typecheck": "vue-tsc --noEmit -p tsconfig.renderer.json && tsc --noEmit -p tsconfig.electron.json", + "build": "pnpm run typecheck && pnpm run build:renderer && pnpm run build:electron", + "test": "vitest run", + "dist": "pnpm run build && electron-builder", + "dist:win": "pnpm run build && electron-builder --win --x64", + "icon:build": "node scripts/build-icon.cjs" + }, + "build": { + "appId": "com.jxxyk.genuineqingquwang", + "productName": "正版情趣王", + "copyright": "Copyright © 2026 星驿科技", + "asar": true, + "asarUnpack": [ + "node_modules/sharp/**/*", + "node_modules/@img/**/*" + ], + "directories": { + "output": "release", + "buildResources": "build" + }, + "files": [ + "dist/**/*", + "dist-electron/**/*", + "package.json" + ], + "win": { + "icon": "build/icon.png", + "target": [ + { + "target": "nsis", + "arch": [ + "x64" + ] + } + ], + "artifactName": "正版情趣王-Setup-${version}.${ext}" + }, + "nsis": { + "oneClick": false, + "allowToChangeInstallationDirectory": true, + "createDesktopShortcut": true, + "createStartMenuShortcut": true, + "shortcutName": "正版情趣王", + "uninstallDisplayName": "正版情趣王" + }, + "mac": { + "icon": "build/icon.png", + "category": "public.app-category.graphics-design", + "artifactName": "正版情趣王-${version}.${ext}" + } + }, + "dependencies": { + "@lucide/vue": "^1.34.0", + "node-machine-id": "^1.1.12", + "sharp": "^0.35.3", + "vue": "^3.5.41" + }, + "devDependencies": { + "@types/node": "^26.3.0", + "@vitejs/plugin-vue": "^6.0.8", + "concurrently": "^10.0.5", + "cross-env": "^10.1.0", + "electron": "^44.0.0", + "electron-builder": "^26.15.3", + "typescript": "^5.9.3", + "vite": "^8.2.2", + "vitest": "^4.1.11", + "vue-tsc": "^3.3.11", + "wait-on": "^9.1.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..f9fc412 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,3701 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@lucide/vue': + specifier: ^1.34.0 + version: 1.34.0(vue@3.5.41(typescript@5.9.3)) + node-machine-id: + specifier: ^1.1.12 + version: 1.1.12 + sharp: + specifier: ^0.35.3 + version: 0.35.3(@types/node@26.3.0) + vue: + specifier: ^3.5.41 + version: 3.5.41(typescript@5.9.3) + devDependencies: + '@types/node': + specifier: ^26.3.0 + version: 26.3.0 + '@vitejs/plugin-vue': + specifier: ^6.0.8 + version: 6.0.8(vite@8.2.2(@types/node@26.3.0)(jiti@2.7.0))(vue@3.5.41(typescript@5.9.3)) + concurrently: + specifier: ^10.0.5 + version: 10.0.5 + cross-env: + specifier: ^10.1.0 + version: 10.1.0 + electron: + specifier: ^44.0.0 + version: 44.0.0 + electron-builder: + specifier: ^26.15.3 + version: 26.15.3(electron-builder-squirrel-windows@26.15.3) + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vite: + specifier: ^8.2.2 + version: 8.2.2(@types/node@26.3.0)(jiti@2.7.0) + vitest: + specifier: ^4.1.11 + version: 4.1.11(@types/node@26.3.0)(vite@8.2.2(@types/node@26.3.0)(jiti@2.7.0)) + vue-tsc: + specifier: ^3.3.11 + version: 3.3.11(typescript@5.9.3) + wait-on: + specifier: ^9.1.0 + version: 9.1.0 + +packages: + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + + '@electron-internal/extract-zip@1.0.5': + resolution: {integrity: sha512-+bqFCP98pLI0Tt0XQo1TmlXtwjWchISndDOxCkEcIuUgXWpBnLyRI+2DU+mesvnMMX6L1XDqYNA0lXNDHd/yiA==} + engines: {node: '>=22.12.0'} + + '@electron/asar@3.4.1': + resolution: {integrity: sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==} + engines: {node: '>=10.12.0'} + hasBin: true + + '@electron/fuses@1.8.0': + resolution: {integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==} + hasBin: true + + '@electron/get@3.1.0': + resolution: {integrity: sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==} + engines: {node: '>=14'} + + '@electron/get@5.1.0': + resolution: {integrity: sha512-3kSBtG8ObcTVfXanm5vVJ6UnBLEVmVsRk1M+vGqCuMBV+XLCbJYuWQful+yIy0GQDsSlK0kHEriEHn7SPk4EnA==} + engines: {node: '>=22.12.0'} + + '@electron/notarize@2.5.0': + resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==} + engines: {node: '>= 10.0.0'} + + '@electron/osx-sign@1.3.3': + resolution: {integrity: sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==} + engines: {node: '>=12.0.0'} + hasBin: true + + '@electron/rebuild@4.2.0': + resolution: {integrity: sha512-RKL/O+jGoXJMxrx/5771y1n0xTKmFuOYGO3gMmwypBM6rsH0kou0mswwdXA2JrhIkE4xyC7v9vGk0n6NPzgOxQ==} + engines: {node: '>=22.12.0'} + hasBin: true + + '@electron/universal@2.0.3': + resolution: {integrity: sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g==} + engines: {node: '>=16.4'} + + '@electron/windows-sign@1.2.2': + resolution: {integrity: sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==} + engines: {node: '>=14.14'} + hasBin: true + + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@epic-web/invariant@1.0.0': + resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} + + '@hapi/address@5.1.1': + resolution: {integrity: sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==} + engines: {node: '>=14.0.0'} + + '@hapi/formula@3.0.2': + resolution: {integrity: sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==} + + '@hapi/hoek@11.0.7': + resolution: {integrity: sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==} + + '@hapi/pinpoint@2.0.1': + resolution: {integrity: sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==} + + '@hapi/tlds@1.1.7': + resolution: {integrity: sha512-MgNjRwy9Ti92yVAixLmDc8dd1bJIKwO9qlWCfFQRwRmUEDPQHYn4G6hwPFvFGUTzAa0FsS+inMjLin7GnyBRhA==} + engines: {node: '>=14.0.0'} + + '@hapi/topo@6.0.2': + resolution: {integrity: sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.35.3': + resolution: {integrity: sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.35.3': + resolution: {integrity: sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [darwin] + + '@img/sharp-freebsd-wasm32@0.35.3': + resolution: {integrity: sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.2': + resolution: {integrity: sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.3.2': + resolution: {integrity: sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.3.2': + resolution: {integrity: sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.3.2': + resolution: {integrity: sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.3.2': + resolution: {integrity: sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.3.2': + resolution: {integrity: sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.3.2': + resolution: {integrity: sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.3.2': + resolution: {integrity: sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': + resolution: {integrity: sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.3.2': + resolution: {integrity: sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.35.3': + resolution: {integrity: sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.35.3': + resolution: {integrity: sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==} + engines: {node: '>=20.9.0'} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.35.3': + resolution: {integrity: sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.35.3': + resolution: {integrity: sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.35.3': + resolution: {integrity: sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==} + engines: {node: '>=20.9.0'} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.35.3': + resolution: {integrity: sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.35.3': + resolution: {integrity: sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.35.3': + resolution: {integrity: sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.35.3': + resolution: {integrity: sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.3': + resolution: {integrity: sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==} + engines: {node: '>=20.9.0'} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.35.3': + resolution: {integrity: sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.35.3': + resolution: {integrity: sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==} + engines: {node: ^20.9.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.35.3': + resolution: {integrity: sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [win32] + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@lucide/vue@1.34.0': + resolution: {integrity: sha512-eB48kx1oe9O6mJAg0gFWgv66y4rhYJYuhfWF8wIz/YBFPDDHWHI7+kRJpkvz/8kePY6ddbwxXIGfP8E54wlGhA==} + peerDependencies: + vue: '>=3.0.1' + + '@malept/cross-spawn-promise@2.0.0': + resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==} + engines: {node: '>= 12.13.0'} + + '@malept/flatpak-bundler@0.4.0': + resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} + engines: {node: '>= 10.0.0'} + + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + + '@noble/hashes@2.3.0': + resolution: {integrity: sha512-oN+QwyX7VSHotibwubG3kpzbwKrfnyR6OOO+3Nk/53ADL7FmgHHz4TgrbaYKvvOw09u6QTx0oiH1cNCIOuN0CQ==} + engines: {node: '>= 20.19.0'} + + '@oxc-project/types@0.146.0': + resolution: {integrity: sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==} + + '@peculiar/asn1-schema@2.9.4': + resolution: {integrity: sha512-GjzePcT9Iw8NzeOPf73iNS9xM+TBhd/FilAfP+RQGkTMQJTVWtytN3JHJACCjf/ABNau5S7mS3g+DcuxmRgYEg==} + engines: {node: '>=14'} + + '@peculiar/json-schema@1.1.12': + resolution: {integrity: sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==} + engines: {node: '>=8.0.0'} + + '@peculiar/utils@2.0.3': + resolution: {integrity: sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==} + + '@peculiar/webcrypto@1.7.1': + resolution: {integrity: sha512-ODOov0sGMJMf3jPonOkgGqPknTsu+DdQ7kD++gz8aI+aFMOMHFbWAA2taqXXVTdP+OTOQR/znGvSpmkeI0WTYQ==} + engines: {node: '>=14.18.0'} + + '@rolldown/binding-android-arm-eabi@1.2.5': + resolution: {integrity: sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@rolldown/binding-android-arm64@1.2.5': + resolution: {integrity: sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.2.5': + resolution: {integrity: sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.2.5': + resolution: {integrity: sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.2.5': + resolution: {integrity: sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.2.5': + resolution: {integrity: sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.2.5': + resolution: {integrity: sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.2.5': + resolution: {integrity: sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-ppc64-gnu@1.2.5': + resolution: {integrity: sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@rolldown/binding-linux-s390x-gnu@1.2.5': + resolution: {integrity: sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.2.5': + resolution: {integrity: sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.2.5': + resolution: {integrity: sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.2.5': + resolution: {integrity: sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-win32-arm64-msvc@1.2.5': + resolution: {integrity: sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.2.5': + resolution: {integrity: sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/fs-extra@9.0.13': + resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + + '@types/http-cache-semantics@4.2.0': + resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} + + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@24.13.3': + resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} + + '@types/node@26.3.0': + resolution: {integrity: sha512-L3fgrnchriRC2ExBflb8j4uZZURHZfQsmQeyVzhjcHW4kkwVyo8/0h1B2MVzMTrYUJYu6G7EWs14hW/L9putqw==} + + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + + '@vitejs/plugin-vue@6.0.8': + resolution: {integrity: sha512-0ZjgOg7oO6farnNGup7yvoM/YXZV84OZxHAwtflItNa/6zzQyVb5LNxyea3FEKEX2XlagIKzrlH7wwxkKgtiew==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vue: ^3.2.25 + + '@vitest/expect@4.1.11': + resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} + + '@vitest/mocker@4.1.11': + resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.11': + resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} + + '@vitest/runner@4.1.11': + resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} + + '@vitest/snapshot@4.1.11': + resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} + + '@vitest/spy@4.1.11': + resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} + + '@vitest/utils@4.1.11': + resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + + '@vue/compiler-core@3.5.41': + resolution: {integrity: sha512-q0Xtv/F9w2YO/7htQhtiL+Ev2WCJbe5N2hc+XfgyKkEKqWpSxknmT8QOuGdEKNdjPq0c3F7rNpFkTo3Kfrm7pg==} + + '@vue/compiler-dom@3.5.41': + resolution: {integrity: sha512-oKacVfNglLvGjnS6BXOlGL7EyG2h8X03pqXCjzotRZUaXGjbrTJUnVAQjrCqUnS+lyu31nwQjZY/d817GmCnfw==} + + '@vue/compiler-sfc@3.5.41': + resolution: {integrity: sha512-XJhip7R2wy6vX3knCxdZN4KracFaZUef58s1KYewqluedHIJaPIVfXoYT7MF1F8nCvv6k8bWWxDC8opMkg1VTQ==} + + '@vue/compiler-ssr@3.5.41': + resolution: {integrity: sha512-U3v5OejKEGqOI0Wy0+Sz7hGuIFZHA4LSXzrNM3IMIeDyJEBBfTpX26n3SDgToRpP2bLc9FfI2j/kSgcJ8Emq5A==} + + '@vue/language-core@3.3.11': + resolution: {integrity: sha512-QJmpliwAVpC/OxubIByPAhNzsQPRc8/gxlN2qnVzVfIMjMDz/9RnXRFoetjz5yEgXVXyp4LqhXq3V53PjmNzFw==} + + '@vue/reactivity@3.5.41': + resolution: {integrity: sha512-rznsqKM0np0x18EjzF8x88MpEhdNsffbvFbckLL5+oUKz1BxAImEmO7J1ArRYSyo6aQaVoBDp7jEkT91OOxydA==} + + '@vue/runtime-core@3.5.41': + resolution: {integrity: sha512-Vcry58hiAKwGen9Z1jUZE0feFsNArPCMOImYI8el48A9Idf6DuQYD0U05zZIF2Iad1hGhPSvcbBbAOhNr55fhg==} + + '@vue/runtime-dom@3.5.41': + resolution: {integrity: sha512-3vVBahVBS9+U6cmXBLyb8nE6/yYo4J/CGI9eVFs3KiMc0YHuudwKyShTD65jtJy/L9PUUxNAFu4cj4LiJ0UFbw==} + + '@vue/server-renderer@3.5.41': + resolution: {integrity: sha512-n6hx/pNFfbD6SuyeuMVkvqox8bwf/ET9JlA/kAz/imw8sw++wkqKe2mHX5KutjPpbKE4Z56yTHszoOjGMI9igQ==} + + '@vue/shared@3.5.41': + resolution: {integrity: sha512-IOnwSCma8j+9xJT6b8H0dEYidC80NsYmNMlZxRsukYcSoGaDBohog5hDxzeUXdFeGWFA++vWvxqOmrr96VlqMA==} + + '@xmldom/xmldom@0.8.15': + resolution: {integrity: sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==} + engines: {node: '>=10.0.0'} + + abbrev@4.0.0: + resolution: {integrity: sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==} + engines: {node: ^20.17.0 || >=22.9.0} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + alien-signals@3.2.1: + resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.3.0: + resolution: {integrity: sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + app-builder-lib@26.15.3: + resolution: {integrity: sha512-2VnyWkqsP5v5XbBhL3tD5Syx8iNPBYsoU7kY4S2fz7wg8Rj/nztWKCUzGKaFRTv0Xwf3/H058CR1Kvtd/3lRow==} + engines: {node: '>=14.0.0'} + peerDependencies: + dmg-builder: 26.15.3 + electron-builder-squirrel-windows: 26.15.3 + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + asn1js@3.0.10: + resolution: {integrity: sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==} + engines: {node: '>=12.0.0'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + async-exit-hook@2.0.1: + resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==} + engines: {node: '>=0.12.0'} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + + aws4@1.13.2: + resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + + axios@1.19.0: + resolution: {integrity: sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + boolean@3.2.0: + resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + brace-expansion@1.1.18: + resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==} + + brace-expansion@2.1.4: + resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==} + + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} + engines: {node: 20 || >=22} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + builder-util-runtime@9.7.0: + resolution: {integrity: sha512-g/kR520giAFYkSXTzcmF3kqQq7wi8F6N6SzeDgZrqTBN+VHdmgWOyTdD1yD7AATDId/yXLvuP34CxW46/BwCdw==} + engines: {node: '>=12.0.0'} + + builder-util@26.15.3: + resolution: {integrity: sha512-q2hn7Mbo2nFNkVekPiHFx6Nfo3hURmES3tfBn+k5Pqxl2RkmP3QGqZUhH/q9Pch/4G05NRhPjDlVj1O8q4Txvw==} + engines: {node: '>=14.0.0'} + + bytestreamjs@2.0.1: + resolution: {integrity: sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==} + engines: {node: '>=6.0.0'} + + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + chromium-pickle-js@0.2.0: + resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==} + + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + engines: {node: '>=8'} + + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} + + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@5.1.0: + resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} + engines: {node: '>= 6'} + + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + + compare-version@0.1.2: + resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} + engines: {node: '>=0.10.0'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concurrently@10.0.5: + resolution: {integrity: sha512-JaP/CoftUrCcAFW/g//RbgEGwlelnEae6cfBLgH6ZdO6s8jPkn6p9SB9u6pdVxYXoiSnFqseOlHfrEfF82TVOg==} + engines: {node: '>=22'} + hasBin: true + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cross-dirname@0.1.0: + resolution: {integrity: sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==} + + cross-env@10.1.0: + resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==} + engines: {node: '>=20'} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + detect-node@2.1.0: + resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + + dir-compare@4.2.0: + resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} + + dmg-builder@26.15.3: + resolution: {integrity: sha512-O3zJUFUYHJKgzPqioHxfxzBzlSC1eXCSr79gMSBKBP5AgjjpmrydMsMLotEg9fAJF36vdUncb+4ndRNxoPdlSQ==} + + dotenv-expand@11.0.7: + resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} + engines: {node: '>=12'} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexer2@0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-builder-squirrel-windows@26.15.3: + resolution: {integrity: sha512-Jc19XPV9y9+2bAdZPkXuVNGNIEFBq9poHC61l8Kv6FdK7DRG3+Ic0rerC0DXOaeHNz8yW0fg/JnF8GQROOF5MA==} + + electron-builder@26.15.3: + resolution: {integrity: sha512-a1KM5heqS3gQCZzizXEI8RjJy3QVogULPdeSknt76uLDpBIW/HDGsMg/XgP0riP6PI9COsRvFITKKGDqA8fJxA==} + engines: {node: '>=14.0.0'} + hasBin: true + + electron-publish@26.15.3: + resolution: {integrity: sha512-g/2bn8YTavY4cuS5F+jOS7zmZbXXBV8KZ8yHKfJjFPoKtzBqrpCdNPxBd3tqdBwP7BVd0lGzf7Bk2s0KesWZ4Q==} + + electron-winstaller@5.4.0: + resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} + engines: {node: '>=8.0.0'} + + electron@44.0.0: + resolution: {integrity: sha512-FkTqPrFPZYljdPI5b7KORGsJTd6FgUQDefl5MrU3Xz9R87pAj9JLreIjDqcRN8hJIkFHIou0o8kKzvcpT9qiRQ==} + engines: {node: '>= 22.12.0'} + hasBin: true + + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + env-paths@3.0.0: + resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es6-error@4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.1.6: + resolution: {integrity: sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + filelist@1.0.6: + resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==} + + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} + engines: {node: '>= 6'} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs-extra@11.3.1: + resolution: {integrity: sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==} + engines: {node: '>=14.14'} + + fs-extra@11.4.0: + resolution: {integrity: sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==} + engines: {node: '>=14.14'} + + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + glob@7.2.3: + resolution: {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 + + global-agent@3.0.0: + resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} + engines: {node: '>=10.0'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isbinaryfile@4.0.10: + resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} + engines: {node: '>= 8.0.0'} + + isbinaryfile@5.0.7: + resolution: {integrity: sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==} + engines: {node: '>= 18.0.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isexe@3.1.5: + resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} + engines: {node: '>=18'} + + isexe@4.0.0: + resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==} + engines: {node: '>=20'} + + jake@10.9.4: + resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} + engines: {node: '>=10'} + hasBin: true + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + joi@18.2.5: + resolution: {integrity: sha512-+gEA7rLfaNWx9JzawWPrPetSZwT16NUqHtECDgjyAJreXcs4TM7tx2Pa+VVJJK0YHM83ybrVdaT6UekHH50FJQ==} + engines: {node: '>= 20'} + + js-yaml@4.3.1: + resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsonfile@6.2.1: + resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + lazy-val@1.0.5: + resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} + + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + matcher@3.0.0: + resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} + engines: {node: '>=10'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-abi@4.34.0: + resolution: {integrity: sha512-4Oy5Q6/Ftna9sXyrkdnKypfvm9uWRpxUPvlw4oA192QNMN39aq8k4l36TUUUU/ONw7ivGVi402Ud+UBPVDYh6A==} + engines: {node: '>=22.12.0'} + + node-api-version@0.2.1: + resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==} + + node-gyp@12.4.0: + resolution: {integrity: sha512-OMcPNvqTCFUnNaBlmdgq+lfNqY7gTiSmNRDjY3uAXRyudeKZEZxu3CLtjMQrx4zZxCX2b/mpNqTtwuCJgXhHkw==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-machine-id@1.1.12: + resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==} + + nopt@9.0.0: + resolution: {integrity: sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + obug@2.1.4: + resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} + engines: {node: '>=12.20.0'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pe-library@0.4.1: + resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==} + engines: {node: '>=12', npm: '>=6'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + + pkijs@3.4.0: + resolution: {integrity: sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw==} + engines: {node: '>=16.0.0'} + + plist@3.1.0: + resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} + engines: {node: '>=10.4.0'} + + postcss@8.5.26: + resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} + engines: {node: ^10 || ^12 || >=14} + + postject@1.0.0-alpha.6: + resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} + engines: {node: '>=14.0.0'} + hasBin: true + + proc-log@6.1.0: + resolution: {integrity: sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.2.0: + resolution: {integrity: sha512-BbubeCEyTuQjVMakvJQ/Sxbc93F2pwmbsxONT/ZRrwU7Ua38d8unYTwXpTVLAKJ4BDuH9IGztCjQcd/N/39Dvg==} + engines: {node: '>=16.0.0'} + + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + + read-binary-file-arch@1.0.6: + resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==} + hasBin: true + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resedit@1.7.2: + resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==} + engines: {node: '>=12', npm: '>=6'} + + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + rimraf@2.6.3: + resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + roarr@2.15.4: + resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} + engines: {node: '>=8.0'} + + rolldown@1.2.5: + resolution: {integrity: sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + sanitize-filename@1.6.4: + resolution: {integrity: sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==} + + sax@1.6.1: + resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==} + engines: {node: '>=11.0.0'} + + semver-compare@1.0.0: + resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + serialize-error@7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + + sharp@0.35.3: + resolution: {integrity: sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.9.0: + resolution: {integrity: sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + simple-update-notifier@2.0.0: + resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} + engines: {node: '>=10'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + stat-mode@1.0.0: + resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==} + engines: {node: '>= 6'} + + std-env@4.2.0: + resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + sumchecker@3.0.1: + resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} + engines: {node: '>= 8.0'} + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + tar@7.5.22: + resolution: {integrity: sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==} + engines: {node: '>=18'} + + temp-file@3.4.0: + resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} + + temp@0.9.4: + resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==} + engines: {node: '>=6.0.0'} + + tiny-async-pool@1.3.0: + resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.3.0: + resolution: {integrity: sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.1.1: + resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} + engines: {node: '>=14.0.0'} + + tmp-promise@3.0.3: + resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} + + tmp@0.2.7: + resolution: {integrity: sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==} + engines: {node: '>=14.14'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + truncate-utf8-bytes@1.0.2: + resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + undici-types@8.3.0: + resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} + + undici@6.28.0: + resolution: {integrity: sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==} + engines: {node: '>=18.17'} + + undici@7.29.0: + resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==} + engines: {node: '>=20.18.1'} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unzipper@0.12.5: + resolution: {integrity: sha512-tXYOi9R57Uj/2Z25SOs5RRSzq886MBQj2gY8dPL+xl/kv6s6SvByoKfAtvfVeEuhntWDgjd2o9p2lb4TVPAz0A==} + + utf8-byte-length@1.0.5: + resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vite@8.2.2: + resolution: {integrity: sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.4.0 || ^0.5.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.11: + resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.11 + '@vitest/browser-preview': 4.1.11 + '@vitest/browser-webdriverio': 4.1.11 + '@vitest/coverage-istanbul': 4.1.11 + '@vitest/coverage-v8': 4.1.11 + '@vitest/ui': 4.1.11 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + vscode-uri@3.2.0: + resolution: {integrity: sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg==} + + vue-tsc@3.3.11: + resolution: {integrity: sha512-gOb0B9rtU2+f1dszwPqSH5kAieIF9ReeLhD3kSRNHv5WZZUQz/JdVXW0RTdqhNTMlQkqKzrTTviqKr/4FYZraQ==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + + vue@3.5.41: + resolution: {integrity: sha512-2laE0p+aK+/AOPG/XL/WepOs/GlK755LJ1XECi9kDUrz1FKNw8rb2Xzlw9JS1rqEV55nb0ttsKxVlTCcd+R5cg==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + wait-on@9.1.0: + resolution: {integrity: sha512-PymrLXHLBM1Ju/Xspb2ADUhbPSMvbnuNvy/mN2hWtpbJ3da0h3Ky1LqwKPG5QSVR57liyO0iUpfipYl/s5qNvA==} + engines: {node: '>=20.0.0'} + hasBin: true + + webcrypto-core@1.9.2: + resolution: {integrity: sha512-gsXecm82UQNlTBURJGuqOWy1Ww08S3kZUcr3aOJS02Pk0xLtkfeUAVC0u0xhgdonFme80edSJUIJyuvL/7250Q==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + which@5.0.0: + resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + + which@6.0.1: + resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xmlbuilder@15.1.1: + resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} + engines: {node: '>=8.0'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + yargs@17.7.3: + resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} + engines: {node: '>=12'} + + yargs@18.0.0: + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/parser@7.29.8': + dependencies: + '@babel/types': 7.29.8 + + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@electron-internal/extract-zip@1.0.5': {} + + '@electron/asar@3.4.1': + dependencies: + commander: 5.1.0 + glob: 7.2.3 + minimatch: 3.1.5 + + '@electron/fuses@1.8.0': + dependencies: + chalk: 4.1.2 + fs-extra: 9.1.0 + minimist: 1.2.8 + + '@electron/get@3.1.0': + dependencies: + debug: 4.4.3 + env-paths: 2.2.1 + fs-extra: 8.1.0 + got: 11.8.6 + progress: 2.0.3 + semver: 6.3.1 + sumchecker: 3.0.1 + optionalDependencies: + global-agent: 3.0.0 + transitivePeerDependencies: + - supports-color + + '@electron/get@5.1.0': + dependencies: + debug: 4.4.3 + env-paths: 3.0.0 + graceful-fs: 4.2.11 + progress: 2.0.3 + semver: 7.8.5 + sumchecker: 3.0.1 + optionalDependencies: + undici: 7.29.0 + transitivePeerDependencies: + - supports-color + + '@electron/notarize@2.5.0': + dependencies: + debug: 4.4.3 + fs-extra: 9.1.0 + promise-retry: 2.0.1 + transitivePeerDependencies: + - supports-color + + '@electron/osx-sign@1.3.3': + dependencies: + compare-version: 0.1.2 + debug: 4.4.3 + fs-extra: 10.1.0 + isbinaryfile: 4.0.10 + minimist: 1.2.8 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@electron/rebuild@4.2.0': + dependencies: + '@malept/cross-spawn-promise': 2.0.0 + debug: 4.4.3 + node-abi: 4.34.0 + node-api-version: 0.2.1 + node-gyp: 12.4.0 + read-binary-file-arch: 1.0.6 + transitivePeerDependencies: + - supports-color + + '@electron/universal@2.0.3': + dependencies: + '@electron/asar': 3.4.1 + '@malept/cross-spawn-promise': 2.0.0 + debug: 4.4.3 + dir-compare: 4.2.0 + fs-extra: 11.4.0 + minimatch: 9.0.9 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@electron/windows-sign@1.2.2': + dependencies: + cross-dirname: 0.1.0 + debug: 4.4.3 + fs-extra: 11.4.0 + minimist: 1.2.8 + postject: 1.0.0-alpha.6 + transitivePeerDependencies: + - supports-color + optional: true + + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@epic-web/invariant@1.0.0': {} + + '@hapi/address@5.1.1': + dependencies: + '@hapi/hoek': 11.0.7 + + '@hapi/formula@3.0.2': {} + + '@hapi/hoek@11.0.7': {} + + '@hapi/pinpoint@2.0.1': {} + + '@hapi/tlds@1.1.7': {} + + '@hapi/topo@6.0.2': + dependencies: + '@hapi/hoek': 11.0.7 + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.3.2 + optional: true + + '@img/sharp-darwin-x64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.3.2 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.3.2': + optional: true + + '@img/sharp-libvips-darwin-x64@1.3.2': + optional: true + + '@img/sharp-libvips-linux-arm64@1.3.2': + optional: true + + '@img/sharp-libvips-linux-arm@1.3.2': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.3.2': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.3.2': + optional: true + + '@img/sharp-libvips-linux-s390x@1.3.2': + optional: true + + '@img/sharp-libvips-linux-x64@1.3.2': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.3.2': + optional: true + + '@img/sharp-linux-arm64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.2 + optional: true + + '@img/sharp-linux-arm@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.2 + optional: true + + '@img/sharp-linux-ppc64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.2 + optional: true + + '@img/sharp-linux-riscv64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.2 + optional: true + + '@img/sharp-linux-s390x@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.3.2 + optional: true + + '@img/sharp-linux-x64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.3.2 + optional: true + + '@img/sharp-linuxmusl-arm64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + optional: true + + '@img/sharp-linuxmusl-x64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + optional: true + + '@img/sharp-wasm32@0.35.3': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 + optional: true + + '@img/sharp-win32-arm64@0.35.3': + optional: true + + '@img/sharp-win32-ia32@0.35.3': + optional: true + + '@img/sharp-win32-x64@0.35.3': + optional: true + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.3 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@lucide/vue@1.34.0(vue@3.5.41(typescript@5.9.3))': + dependencies: + vue: 3.5.41(typescript@5.9.3) + + '@malept/cross-spawn-promise@2.0.0': + dependencies: + cross-spawn: 7.0.6 + + '@malept/flatpak-bundler@0.4.0': + dependencies: + debug: 4.4.3 + fs-extra: 9.1.0 + lodash: 4.18.1 + tmp-promise: 3.0.3 + transitivePeerDependencies: + - supports-color + + '@noble/hashes@1.4.0': {} + + '@noble/hashes@2.3.0': {} + + '@oxc-project/types@0.146.0': {} + + '@peculiar/asn1-schema@2.9.4': + dependencies: + '@peculiar/utils': 2.0.3 + asn1js: 3.0.10 + tslib: 2.8.1 + + '@peculiar/json-schema@1.1.12': + dependencies: + tslib: 2.8.1 + + '@peculiar/utils@2.0.3': + dependencies: + tslib: 2.8.1 + + '@peculiar/webcrypto@1.7.1': + dependencies: + '@peculiar/asn1-schema': 2.9.4 + '@peculiar/json-schema': 1.1.12 + '@peculiar/utils': 2.0.3 + tslib: 2.8.1 + webcrypto-core: 1.9.2 + + '@rolldown/binding-android-arm-eabi@1.2.5': + optional: true + + '@rolldown/binding-android-arm64@1.2.5': + optional: true + + '@rolldown/binding-darwin-arm64@1.2.5': + optional: true + + '@rolldown/binding-darwin-x64@1.2.5': + optional: true + + '@rolldown/binding-freebsd-x64@1.2.5': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.2.5': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.2.5': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.2.5': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.2.5': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.2.5': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.2.5': + optional: true + + '@rolldown/binding-linux-x64-musl@1.2.5': + optional: true + + '@rolldown/binding-openharmony-arm64@1.2.5': + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.2.5': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.2.5': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@sindresorhus/is@4.6.0': {} + + '@standard-schema/spec@1.1.0': {} + + '@szmarczak/http-timer@4.0.6': + dependencies: + defer-to-connect: 2.0.1 + + '@types/cacheable-request@6.0.3': + dependencies: + '@types/http-cache-semantics': 4.2.0 + '@types/keyv': 3.1.4 + '@types/node': 26.3.0 + '@types/responselike': 1.0.3 + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.9': {} + + '@types/fs-extra@9.0.13': + dependencies: + '@types/node': 26.3.0 + + '@types/http-cache-semantics@4.2.0': {} + + '@types/keyv@3.1.4': + dependencies: + '@types/node': 26.3.0 + + '@types/ms@2.1.0': {} + + '@types/node@24.13.3': + dependencies: + undici-types: 7.18.2 + + '@types/node@26.3.0': + dependencies: + undici-types: 8.3.0 + + '@types/responselike@1.0.3': + dependencies: + '@types/node': 26.3.0 + + '@vitejs/plugin-vue@6.0.8(vite@8.2.2(@types/node@26.3.0)(jiti@2.7.0))(vue@3.5.41(typescript@5.9.3))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.2.2(@types/node@26.3.0)(jiti@2.7.0) + vue: 3.5.41(typescript@5.9.3) + + '@vitest/expect@4.1.11': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 + chai: 6.2.2 + tinyrainbow: 3.1.1 + + '@vitest/mocker@4.1.11(vite@8.2.2(@types/node@26.3.0)(jiti@2.7.0))': + dependencies: + '@vitest/spy': 4.1.11 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.2.2(@types/node@26.3.0)(jiti@2.7.0) + + '@vitest/pretty-format@4.1.11': + dependencies: + tinyrainbow: 3.1.1 + + '@vitest/runner@4.1.11': + dependencies: + '@vitest/utils': 4.1.11 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.11': + dependencies: + '@vitest/pretty-format': 4.1.11 + '@vitest/utils': 4.1.11 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.11': {} + + '@vitest/utils@4.1.11': + dependencies: + '@vitest/pretty-format': 4.1.11 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.1 + + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/source-map@2.4.28': {} + + '@volar/typescript@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + path-browserify: 1.0.1 + vscode-uri: 3.2.0 + + '@vue/compiler-core@3.5.41': + dependencies: + '@babel/parser': 7.29.8 + '@vue/shared': 3.5.41 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.41': + dependencies: + '@vue/compiler-core': 3.5.41 + '@vue/shared': 3.5.41 + + '@vue/compiler-sfc@3.5.41': + dependencies: + '@babel/parser': 7.29.8 + '@vue/compiler-core': 3.5.41 + '@vue/compiler-dom': 3.5.41 + '@vue/compiler-ssr': 3.5.41 + '@vue/shared': 3.5.41 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.26 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.41': + dependencies: + '@vue/compiler-dom': 3.5.41 + '@vue/shared': 3.5.41 + + '@vue/language-core@3.3.11': + dependencies: + '@volar/language-core': 2.4.28 + '@vue/compiler-dom': 3.5.41 + '@vue/shared': 3.5.41 + alien-signals: 3.2.1 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + picomatch: 4.0.7 + + '@vue/reactivity@3.5.41': + dependencies: + '@vue/shared': 3.5.41 + + '@vue/runtime-core@3.5.41': + dependencies: + '@vue/reactivity': 3.5.41 + '@vue/shared': 3.5.41 + + '@vue/runtime-dom@3.5.41': + dependencies: + '@vue/reactivity': 3.5.41 + '@vue/runtime-core': 3.5.41 + '@vue/shared': 3.5.41 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.41': + dependencies: + '@vue/compiler-ssr': 3.5.41 + '@vue/runtime-dom': 3.5.41 + '@vue/shared': 3.5.41 + + '@vue/shared@3.5.41': {} + + '@xmldom/xmldom@0.8.15': {} + + abbrev@4.0.0: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + agent-base@7.1.4: {} + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.6 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + alien-signals@3.2.1: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.3.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + app-builder-lib@26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3): + dependencies: + '@electron/asar': 3.4.1 + '@electron/fuses': 1.8.0 + '@electron/get': 3.1.0 + '@electron/notarize': 2.5.0 + '@electron/osx-sign': 1.3.3 + '@electron/rebuild': 4.2.0 + '@electron/universal': 2.0.3 + '@malept/flatpak-bundler': 0.4.0 + '@noble/hashes': 2.3.0 + '@peculiar/webcrypto': 1.7.1 + '@types/fs-extra': 9.0.13 + ajv: 8.20.0 + asn1js: 3.0.10 + async-exit-hook: 2.0.1 + builder-util: 26.15.3 + builder-util-runtime: 9.7.0 + chromium-pickle-js: 0.2.0 + ci-info: 4.3.1 + debug: 4.4.3 + dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3) + dotenv: 16.6.1 + dotenv-expand: 11.0.7 + ejs: 3.1.10 + electron-builder-squirrel-windows: 26.15.3(dmg-builder@26.15.3) + electron-publish: 26.15.3 + fs-extra: 10.1.0 + hosted-git-info: 4.1.0 + isbinaryfile: 5.0.7 + jiti: 2.7.0 + js-yaml: 4.3.1 + json5: 2.2.3 + lazy-val: 1.0.5 + minimatch: 10.2.6 + pkijs: 3.4.0 + plist: 3.1.0 + proper-lockfile: 4.1.2 + resedit: 1.7.2 + semver: 7.7.4 + tar: 7.5.22 + temp-file: 3.4.0 + tiny-async-pool: 1.3.0 + unzipper: 0.12.5 + which: 5.0.0 + transitivePeerDependencies: + - supports-color + + argparse@2.0.1: {} + + asn1js@3.0.10: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.2.0 + tslib: 2.8.1 + + assertion-error@2.0.1: {} + + async-exit-hook@2.0.1: {} + + async@3.2.6: {} + + asynckit@0.4.0: {} + + at-least-node@1.0.0: {} + + aws4@1.13.2: {} + + axios@1.19.0: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.6 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + base64-js@1.5.1: {} + + bluebird@3.7.2: {} + + boolean@3.2.0: + optional: true + + brace-expansion@1.1.18: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.1.4: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@5.0.9: + dependencies: + balanced-match: 4.0.4 + + buffer-from@1.1.2: {} + + builder-util-runtime@9.7.0: + dependencies: + debug: 4.4.3 + sax: 1.6.1 + transitivePeerDependencies: + - supports-color + + builder-util@26.15.3: + dependencies: + '@types/debug': 4.1.13 + builder-util-runtime: 9.7.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + fs-extra: 10.1.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + js-yaml: 4.3.1 + sanitize-filename: 1.6.4 + source-map-support: 0.5.21 + stat-mode: 1.0.0 + temp-file: 3.4.0 + tiny-async-pool: 1.3.0 + transitivePeerDependencies: + - supports-color + + bytestreamjs@2.0.1: {} + + cacheable-lookup@5.0.4: {} + + cacheable-request@7.0.4: + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.2.0 + keyv: 4.5.4 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + chai@6.2.2: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.6.2: {} + + chownr@3.0.0: {} + + chromium-pickle-js@0.2.0: {} + + ci-info@4.3.1: {} + + ci-info@4.4.0: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 + + clone-response@1.0.3: + dependencies: + mimic-response: 1.0.1 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@5.1.0: {} + + commander@9.5.0: + optional: true + + compare-version@0.1.2: {} + + concat-map@0.0.1: {} + + concurrently@10.0.5: + dependencies: + chalk: 5.6.2 + rxjs: 7.8.2 + shell-quote: 1.9.0 + supports-color: 10.2.2 + tree-kill: 1.2.2 + yargs: 18.0.0 + + convert-source-map@2.0.0: {} + + core-util-is@1.0.3: {} + + cross-dirname@0.1.0: + optional: true + + cross-env@10.1.0: + dependencies: + '@epic-web/invariant': 1.0.0 + cross-spawn: 7.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + defer-to-connect@2.0.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + optional: true + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + optional: true + + delayed-stream@1.0.0: {} + + detect-libc@2.1.2: {} + + detect-node@2.1.0: + optional: true + + dir-compare@4.2.0: + dependencies: + minimatch: 3.1.5 + p-limit: 3.1.0 + + dmg-builder@26.15.3(electron-builder-squirrel-windows@26.15.3): + dependencies: + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) + builder-util: 26.15.3 + fs-extra: 10.1.0 + js-yaml: 4.3.1 + transitivePeerDependencies: + - electron-builder-squirrel-windows + - supports-color + + dotenv-expand@11.0.7: + dependencies: + dotenv: 16.6.1 + + dotenv@16.6.1: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer2@0.1.4: + dependencies: + readable-stream: 2.3.8 + + ejs@3.1.10: + dependencies: + jake: 10.9.4 + + electron-builder-squirrel-windows@26.15.3(dmg-builder@26.15.3): + dependencies: + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) + builder-util: 26.15.3 + electron-winstaller: 5.4.0 + transitivePeerDependencies: + - dmg-builder + - supports-color + + electron-builder@26.15.3(electron-builder-squirrel-windows@26.15.3): + dependencies: + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) + builder-util: 26.15.3 + builder-util-runtime: 9.7.0 + chalk: 4.1.2 + ci-info: 4.4.0 + dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3) + fs-extra: 10.1.0 + lazy-val: 1.0.5 + simple-update-notifier: 2.0.0 + yargs: 17.7.3 + transitivePeerDependencies: + - electron-builder-squirrel-windows + - supports-color + + electron-publish@26.15.3: + dependencies: + '@types/fs-extra': 9.0.13 + aws4: 1.13.2 + builder-util: 26.15.3 + builder-util-runtime: 9.7.0 + chalk: 4.1.2 + form-data: 4.0.6 + fs-extra: 10.1.0 + lazy-val: 1.0.5 + mime: 2.6.0 + transitivePeerDependencies: + - supports-color + + electron-winstaller@5.4.0: + dependencies: + '@electron/asar': 3.4.1 + debug: 4.4.3 + fs-extra: 7.0.1 + lodash: 4.18.1 + temp: 0.9.4 + optionalDependencies: + '@electron/windows-sign': 1.2.2 + transitivePeerDependencies: + - supports-color + + electron@44.0.0: + dependencies: + '@electron-internal/extract-zip': 1.0.5 + '@electron/get': 5.1.0 + '@types/node': 24.13.3 + transitivePeerDependencies: + - supports-color + + emoji-regex@10.6.0: {} + + emoji-regex@8.0.0: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + entities@7.0.1: {} + + env-paths@2.2.1: {} + + env-paths@3.0.0: {} + + err-code@2.0.3: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@2.3.2: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + es6-error@4.1.1: + optional: true + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: + optional: true + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + expect-type@1.4.0: {} + + exponential-backoff@3.1.3: {} + + fast-deep-equal@3.1.3: {} + + fast-uri@3.1.6: {} + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + filelist@1.0.6: + dependencies: + minimatch: 5.1.9 + + follow-redirects@1.16.0: {} + + form-data@4.0.6: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.1 + universalify: 2.0.1 + + fs-extra@11.3.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.1 + universalify: 2.0.1 + + fs-extra@11.4.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.1 + universalify: 2.0.1 + + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@9.1.0: + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.2.1 + universalify: 2.0.1 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.6.0: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + get-stream@5.2.0: + dependencies: + pump: 3.0.4 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.5 + once: 1.4.0 + path-is-absolute: 1.0.1 + + global-agent@3.0.0: + dependencies: + boolean: 3.2.0 + es6-error: 4.1.1 + matcher: 3.0.0 + roarr: 2.15.4 + semver: 7.8.5 + serialize-error: 7.0.1 + optional: true + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + optional: true + + gopd@1.2.0: {} + + got@11.8.6: + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.3 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.4 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + optional: true + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hosted-git-info@4.1.0: + dependencies: + lru-cache: 6.0.0 + + http-cache-semantics@4.2.0: {} + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + http2-wrapper@1.0.3: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + is-fullwidth-code-point@3.0.0: {} + + isarray@1.0.0: {} + + isbinaryfile@4.0.10: {} + + isbinaryfile@5.0.7: {} + + isexe@2.0.0: {} + + isexe@3.1.5: {} + + isexe@4.0.0: {} + + jake@10.9.4: + dependencies: + async: 3.2.6 + filelist: 1.0.6 + picocolors: 1.1.1 + + jiti@2.7.0: {} + + joi@18.2.5: + dependencies: + '@hapi/address': 5.1.1 + '@hapi/formula': 3.0.2 + '@hapi/hoek': 11.0.7 + '@hapi/pinpoint': 2.0.1 + '@hapi/tlds': 1.1.7 + '@hapi/topo': 6.0.2 + '@standard-schema/spec': 1.1.0 + + js-yaml@4.3.1: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@1.0.0: {} + + json-stringify-safe@5.0.1: + optional: true + + json5@2.2.3: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + jsonfile@6.2.1: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + lazy-val@1.0.5: {} + + lightningcss-android-arm64@1.33.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true + + lightningcss-darwin-x64@1.33.0: + optional: true + + lightningcss-freebsd-x64@1.33.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + + lightningcss-linux-arm64-musl@1.33.0: + optional: true + + lightningcss-linux-x64-gnu@1.33.0: + optional: true + + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + + lightningcss-win32-x64-msvc@1.33.0: + optional: true + + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + + lodash@4.18.1: {} + + lowercase-keys@2.0.0: {} + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + matcher@3.0.0: + dependencies: + escape-string-regexp: 4.0.0 + optional: true + + math-intrinsics@1.1.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@2.6.0: {} + + mimic-response@1.0.1: {} + + mimic-response@3.1.0: {} + + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.9 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.18 + + minimatch@5.1.9: + dependencies: + brace-expansion: 2.1.4 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.4 + + minimist@1.2.8: {} + + minipass@7.1.3: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.3 + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + nanoid@3.3.18: {} + + node-abi@4.34.0: + dependencies: + semver: 7.8.5 + + node-api-version@0.2.1: + dependencies: + semver: 7.8.5 + + node-gyp@12.4.0: + dependencies: + env-paths: 2.2.1 + exponential-backoff: 3.1.3 + graceful-fs: 4.2.11 + nopt: 9.0.0 + proc-log: 6.1.0 + semver: 7.8.5 + tar: 7.5.22 + tinyglobby: 0.2.17 + undici: 6.28.0 + which: 6.0.1 + + node-int64@0.4.0: {} + + node-machine-id@1.1.12: {} + + nopt@9.0.0: + dependencies: + abbrev: 4.0.0 + + normalize-url@6.1.0: {} + + object-keys@1.1.1: + optional: true + + obug@2.1.4: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + p-cancelable@2.1.1: {} + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + path-browserify@1.0.1: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + pathe@2.0.3: {} + + pe-library@0.4.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.7: {} + + pkijs@3.4.0: + dependencies: + '@noble/hashes': 1.4.0 + asn1js: 3.0.10 + bytestreamjs: 2.0.1 + pvtsutils: 1.3.6 + pvutils: 1.2.0 + tslib: 2.8.1 + + plist@3.1.0: + dependencies: + '@xmldom/xmldom': 0.8.15 + base64-js: 1.5.1 + xmlbuilder: 15.1.1 + + postcss@8.5.26: + dependencies: + nanoid: 3.3.18 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postject@1.0.0-alpha.6: + dependencies: + commander: 9.5.0 + optional: true + + proc-log@6.1.0: {} + + process-nextick-args@2.0.1: {} + + progress@2.0.3: {} + + promise-retry@2.0.1: + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + + proxy-from-env@2.1.0: {} + + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.2.0: {} + + quick-lru@5.1.1: {} + + read-binary-file-arch@1.0.6: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + resedit@1.7.2: + dependencies: + pe-library: 0.4.1 + + resolve-alpn@1.2.1: {} + + responselike@2.0.1: + dependencies: + lowercase-keys: 2.0.0 + + retry@0.12.0: {} + + rimraf@2.6.3: + dependencies: + glob: 7.2.3 + + roarr@2.15.4: + dependencies: + boolean: 3.2.0 + detect-node: 2.1.0 + globalthis: 1.0.4 + json-stringify-safe: 5.0.1 + semver-compare: 1.0.0 + sprintf-js: 1.1.3 + optional: true + + rolldown@1.2.5: + dependencies: + '@oxc-project/types': 0.146.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.5 + '@rolldown/binding-android-arm64': 1.2.5 + '@rolldown/binding-darwin-arm64': 1.2.5 + '@rolldown/binding-darwin-x64': 1.2.5 + '@rolldown/binding-freebsd-x64': 1.2.5 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.5 + '@rolldown/binding-linux-arm64-gnu': 1.2.5 + '@rolldown/binding-linux-arm64-musl': 1.2.5 + '@rolldown/binding-linux-ppc64-gnu': 1.2.5 + '@rolldown/binding-linux-s390x-gnu': 1.2.5 + '@rolldown/binding-linux-x64-gnu': 1.2.5 + '@rolldown/binding-linux-x64-musl': 1.2.5 + '@rolldown/binding-openharmony-arm64': 1.2.5 + '@rolldown/binding-win32-arm64-msvc': 1.2.5 + '@rolldown/binding-win32-x64-msvc': 1.2.5 + + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + + safe-buffer@5.1.2: {} + + sanitize-filename@1.6.4: + dependencies: + truncate-utf8-bytes: 1.0.2 + + sax@1.6.1: {} + + semver-compare@1.0.0: + optional: true + + semver@5.7.2: {} + + semver@6.3.1: {} + + semver@7.7.4: {} + + semver@7.8.5: {} + + serialize-error@7.0.1: + dependencies: + type-fest: 0.13.1 + optional: true + + sharp@0.35.3(@types/node@26.3.0): + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.3 + '@img/sharp-darwin-x64': 0.35.3 + '@img/sharp-freebsd-wasm32': 0.35.3 + '@img/sharp-libvips-darwin-arm64': 1.3.2 + '@img/sharp-libvips-darwin-x64': 1.3.2 + '@img/sharp-libvips-linux-arm': 1.3.2 + '@img/sharp-libvips-linux-arm64': 1.3.2 + '@img/sharp-libvips-linux-ppc64': 1.3.2 + '@img/sharp-libvips-linux-riscv64': 1.3.2 + '@img/sharp-libvips-linux-s390x': 1.3.2 + '@img/sharp-libvips-linux-x64': 1.3.2 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + '@img/sharp-linux-arm': 0.35.3 + '@img/sharp-linux-arm64': 0.35.3 + '@img/sharp-linux-ppc64': 0.35.3 + '@img/sharp-linux-riscv64': 0.35.3 + '@img/sharp-linux-s390x': 0.35.3 + '@img/sharp-linux-x64': 0.35.3 + '@img/sharp-linuxmusl-arm64': 0.35.3 + '@img/sharp-linuxmusl-x64': 0.35.3 + '@img/sharp-webcontainers-wasm32': 0.35.3 + '@img/sharp-win32-arm64': 0.35.3 + '@img/sharp-win32-ia32': 0.35.3 + '@img/sharp-win32-x64': 0.35.3 + '@types/node': 26.3.0 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shell-quote@1.9.0: {} + + siginfo@2.0.0: {} + + signal-exit@3.0.7: {} + + simple-update-notifier@2.0.0: + dependencies: + semver: 7.8.5 + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + sprintf-js@1.1.3: + optional: true + + stackback@0.0.2: {} + + stat-mode@1.0.0: {} + + std-env@4.2.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.3.0 + + sumchecker@3.0.1: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + supports-color@10.2.2: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + tar@7.5.22: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 + + temp-file@3.4.0: + dependencies: + async-exit-hook: 2.0.1 + fs-extra: 10.1.0 + + temp@0.9.4: + dependencies: + mkdirp: 0.5.6 + rimraf: 2.6.3 + + tiny-async-pool@1.3.0: + dependencies: + semver: 5.7.2 + + tinybench@2.9.0: {} + + tinyexec@1.3.0: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + tinyrainbow@3.1.1: {} + + tmp-promise@3.0.3: + dependencies: + tmp: 0.2.7 + + tmp@0.2.7: {} + + tree-kill@1.2.2: {} + + truncate-utf8-bytes@1.0.2: + dependencies: + utf8-byte-length: 1.0.5 + + tslib@2.8.1: {} + + type-fest@0.13.1: + optional: true + + typescript@5.9.3: {} + + undici-types@7.18.2: {} + + undici-types@8.3.0: {} + + undici@6.28.0: {} + + undici@7.29.0: + optional: true + + universalify@0.1.2: {} + + universalify@2.0.1: {} + + unzipper@0.12.5: + dependencies: + bluebird: 3.7.2 + duplexer2: 0.1.4 + fs-extra: 11.3.1 + graceful-fs: 4.2.11 + node-int64: 0.4.0 + + utf8-byte-length@1.0.5: {} + + util-deprecate@1.0.2: {} + + vite@8.2.2(@types/node@26.3.0)(jiti@2.7.0): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.26 + rolldown: 1.2.5 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 26.3.0 + fsevents: 2.3.3 + jiti: 2.7.0 + + vitest@4.1.11(@types/node@26.3.0)(vite@8.2.2(@types/node@26.3.0)(jiti@2.7.0)): + dependencies: + '@vitest/expect': 4.1.11 + '@vitest/mocker': 4.1.11(vite@8.2.2(@types/node@26.3.0)(jiti@2.7.0)) + '@vitest/pretty-format': 4.1.11 + '@vitest/runner': 4.1.11 + '@vitest/snapshot': 4.1.11 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 + magic-string: 0.30.21 + obug: 2.1.4 + pathe: 2.0.3 + picomatch: 4.0.7 + std-env: 4.2.0 + tinybench: 2.9.0 + tinyexec: 1.3.0 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.1 + vite: 8.2.2(@types/node@26.3.0)(jiti@2.7.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 26.3.0 + transitivePeerDependencies: + - msw + + vscode-uri@3.2.0: {} + + vue-tsc@3.3.11(typescript@5.9.3): + dependencies: + '@volar/typescript': 2.4.28 + '@vue/language-core': 3.3.11 + typescript: 5.9.3 + + vue@3.5.41(typescript@5.9.3): + dependencies: + '@vue/compiler-dom': 3.5.41 + '@vue/compiler-sfc': 3.5.41 + '@vue/runtime-dom': 3.5.41 + '@vue/server-renderer': 3.5.41 + '@vue/shared': 3.5.41 + optionalDependencies: + typescript: 5.9.3 + + wait-on@9.1.0: + dependencies: + axios: 1.19.0 + joi: 18.2.5 + lodash: 4.18.1 + minimist: 1.2.8 + rxjs: 7.8.2 + transitivePeerDependencies: + - debug + - supports-color + + webcrypto-core@1.9.2: + dependencies: + '@peculiar/asn1-schema': 2.9.4 + '@peculiar/json-schema': 1.1.12 + '@peculiar/utils': 2.0.3 + asn1js: 3.0.10 + tslib: 2.8.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + which@5.0.0: + dependencies: + isexe: 3.1.5 + + which@6.0.1: + dependencies: + isexe: 4.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.2.0 + + wrappy@1.0.2: {} + + xmlbuilder@15.1.1: {} + + y18n@5.0.8: {} + + yallist@4.0.0: {} + + yallist@5.0.0: {} + + yargs-parser@21.1.1: {} + + yargs-parser@22.0.0: {} + + yargs@17.7.3: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yargs@18.0.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 7.2.0 + y18n: 5.0.8 + yargs-parser: 22.0.0 + + yocto-queue@0.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..dd6d453 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,7 @@ +supportedArchitectures: + os: + - current + - win32 + cpu: + - current + - x64 diff --git a/scripts/build-icon.cjs b/scripts/build-icon.cjs new file mode 100644 index 0000000..70d4ba0 --- /dev/null +++ b/scripts/build-icon.cjs @@ -0,0 +1,16 @@ +const fs = require('node:fs/promises') +const path = require('node:path') +const sharp = require('sharp') + +async function main() { + const source = path.resolve(__dirname, '../build/icon.svg') + const output = path.resolve(__dirname, '../build/icon.png') + await fs.mkdir(path.dirname(output), { recursive: true }) + await sharp(source).resize(512, 512).png().toFile(output) + process.stdout.write(`icon=${output}\n`) +} + +main().catch((error) => { + console.error(error) + process.exitCode = 1 +}) diff --git a/scripts/clean-electron.cjs b/scripts/clean-electron.cjs new file mode 100644 index 0000000..374e0ad --- /dev/null +++ b/scripts/clean-electron.cjs @@ -0,0 +1,5 @@ +const fs = require('node:fs') +const path = require('node:path') + +// 编译前只清理可再生的 Electron 输出,避免旧测试产物被误打进安装包。 +fs.rmSync(path.resolve(__dirname, '../dist-electron'), { recursive: true, force: true }) diff --git a/src/env.d.ts b/src/env.d.ts new file mode 100644 index 0000000..03a3ef0 --- /dev/null +++ b/src/env.d.ts @@ -0,0 +1,15 @@ +/// + +import type { DesktopBridge } from './shared/types' + +declare global { + interface Window { + desktop: DesktopBridge + } +} + +declare module 'node-machine-id' { + export function machineIdSync(original?: boolean): string +} + +export {} diff --git a/src/renderer/App.vue b/src/renderer/App.vue new file mode 100644 index 0000000..2ffa603 --- /dev/null +++ b/src/renderer/App.vue @@ -0,0 +1,720 @@ + + + diff --git a/src/renderer/main.ts b/src/renderer/main.ts new file mode 100644 index 0000000..e10189a --- /dev/null +++ b/src/renderer/main.ts @@ -0,0 +1,10 @@ +import { createApp } from 'vue' +import App from './App.vue' +import './styles.css' +import { createMockDesktopBridge } from './mock-bridge' + +if (import.meta.env.DEV && !window.desktop) { + window.desktop = createMockDesktopBridge() +} + +createApp(App).mount('#app') diff --git a/src/renderer/mock-bridge.ts b/src/renderer/mock-bridge.ts new file mode 100644 index 0000000..64a21c3 --- /dev/null +++ b/src/renderer/mock-bridge.ts @@ -0,0 +1,106 @@ +import type { + DesktopBridge, + ImageFileItem, + LicenseViewState, + ProcessProgress, + VersionInfo, +} from '../shared/types' + +/** + * 仅供普通浏览器中的视觉验收使用;Electron 环境始终由 preload 提供真实能力。 + */ +export function createMockDesktopBridge(): DesktopBridge { + const mode = new URLSearchParams(window.location.search).get('demo') || 'workspace' + const progressListeners = new Set<(progress: ProcessProgress) => void>() + const availableUpdate: VersionInfo = { + updateAvailable: true, + latestVersion: 'v1.0.1', + releaseNotes: '

1、优化体验

', + downloadUrl: 'https://cdn.example.com/genuine-qingquwang.exe', + enforce: true, + } + + const activeLicense: LicenseViewState = { + status: 'active', + message: '授权有效', + offline: false, + session: { + licenseCodeMask: 'JXIP-****-****-****-8Q7M', + deviceMask: 'A2C91D…7F06B8', + expiresAt: '2027-08-26T06:00:00+08:00', + maxDevices: 1, + }, + version: mode === 'update' ? availableUpdate : undefined, + } + + return { + getAppInfo: async () => ({ + name: '正版情趣王', + version: '1.0.0', + platform: 'win32', + deviceName: 'DESKTOP-TENCENT', + }), + getLicenseState: async () => mode === 'activation' + ? { status: 'unlicensed', message: '输入激活码后即可开始使用', offline: false } + : activeLicense, + activate: async () => activeLicense, + validateLicense: async () => activeLicense, + clearLicense: async () => ({ status: 'unlicensed', message: '本机授权凭据已清除', offline: false }), + checkVersion: async () => mode === 'update' + ? availableUpdate + : { updateAvailable: false, enforce: false }, + downloadUpdate: async () => undefined, + selectImages: async () => [ + 'C:\\Product\\主图-蓝色.jpg', + 'C:\\Product\\详情页-01.jpg', + 'C:\\Product\\详情页-02.jpg', + ], + selectFolder: async () => ['C:\\Product\\新品批次'], + selectOutputDirectory: async () => 'D:\\正版情趣王\\输出', + pathsForFiles: () => [], + inspectImages: async (paths) => paths.flatMap((filePath, pathIndex) => { + const count = filePath.endsWith('新品批次') ? 4 : 1 + return Array.from({ length: count }, (_, nestedIndex): ImageFileItem => { + const index = pathIndex + nestedIndex + 1 + const name = count > 1 ? `新品-${String(index).padStart(2, '0')}.jpg` : filePath.split('\\').pop() || `图片-${index}.jpg` + return { + id: `${filePath}-${nestedIndex}`, + path: count > 1 ? `${filePath}\\${name}` : filePath, + name, + size: 485_000 + index * 127_000, + width: 1200, + height: 1600, + status: 'pending', + } + }) + }), + processImages: async (options) => { + for (let index = 0; index < options.paths.length; index++) { + const item: ImageFileItem = { + id: options.paths[index], + path: options.paths[index], + name: options.paths[index].split('\\').pop() || '图片.jpg', + size: 612_000, + width: 1200, + height: 1600, + status: 'completed', + outputPath: `${options.paths[index]}.${options.outputFormat === 'file-jpg' ? 'file.jpg' : 'file'}`, + } + progressListeners.forEach((listener) => listener({ + current: index + 1, + total: options.paths.length, + percent: Math.round(((index + 1) / options.paths.length) * 100), + item, + cancelled: false, + })) + } + return { total: options.paths.length, completed: options.paths.length, failed: 0, cancelled: false } + }, + cancelProcessing: async () => undefined, + revealItem: async () => undefined, + onProcessProgress: (callback) => { + progressListeners.add(callback) + return () => progressListeners.delete(callback) + }, + } +} diff --git a/src/renderer/styles.css b/src/renderer/styles.css new file mode 100644 index 0000000..4cf01db --- /dev/null +++ b/src/renderer/styles.css @@ -0,0 +1,277 @@ +:root { + font-family: "HarmonyOS Sans SC", "Microsoft YaHei UI", "PingFang SC", system-ui, sans-serif; + color: #202938; + background: #f4f7fb; + font-synthesis: none; + text-rendering: optimizeLegibility; + --blue: #1769e0; + --blue-deep: #0d55bd; + --blue-pale: #edf4ff; + --teal: #1cab9c; + --ink: #202938; + --muted: #717b8d; + --subtle: #99a2b0; + --line: #e4e9f0; + --canvas: #f4f7fb; + --surface: #ffffff; + --danger: #d94f4f; + --shadow: 0 14px 40px rgba(31, 49, 79, 0.09); +} + +* { box-sizing: border-box; } +html, body, #app { width: 100%; height: 100%; margin: 0; overflow: hidden; } +body { min-width: 1080px; min-height: 680px; } +button, input { font: inherit; } +button { border: 0; } +button:focus-visible, input:focus-visible { outline: 3px solid rgba(23, 105, 224, 0.2); outline-offset: 2px; } +button:disabled { cursor: not-allowed; opacity: 0.52; } + +.app-frame { width: 100%; height: 100%; background: var(--canvas); position: relative; } +.titlebar { + height: 48px; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 156px 0 18px; + background: #f7f9fc; + border-bottom: 1px solid #e9edf3; + -webkit-app-region: drag; + user-select: none; +} +.brand-mini { display: flex; align-items: center; gap: 9px; font-size: 13px; font-weight: 650; color: #293244; letter-spacing: 0.01em; } +.brand-mini-mark { display: grid; place-items: center; width: 27px; height: 27px; color: white; background: var(--blue); border-radius: 7px; } +.titlebar-edition { padding: 2px 7px; color: #5f6d83; background: #e9eef6; border-radius: 4px; font-size: 10px; font-weight: 600; } +.titlebar-status { display: flex; align-items: center; gap: 7px; font-size: 11px; color: #6d7787; } +.status-dot { width: 7px; height: 7px; border-radius: 50%; background: #1bad84; box-shadow: 0 0 0 3px rgba(27, 173, 132, 0.12); } +.status-dot.offline { background: #e0a62e; box-shadow: 0 0 0 3px rgba(224, 166, 46, 0.14); } + +.splash-screen { height: calc(100% - 48px); display: flex; flex-direction: column; align-items: center; justify-content: center; color: #758094; } +.splash-mark { width: 76px; height: 76px; display: grid; place-items: center; color: white; background: var(--blue); border-radius: 20px; box-shadow: 0 18px 36px rgba(23, 105, 224, 0.22); } +.splash-screen h1 { margin: 22px 0 6px; color: var(--ink); font-size: 25px; } +.splash-screen p { margin: 0 0 20px; font-size: 13px; } +.spin { animation: spin 0.85s linear infinite; } +@keyframes spin { to { transform: rotate(360deg); } } + +.activation-shell { height: calc(100% - 48px); overflow: auto; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 38px; background-color: #f1f5fa; background-image: radial-gradient(circle at 1px 1px, rgba(67, 90, 123, 0.075) 1px, transparent 0); background-size: 24px 24px; } +.activation-card { width: min(980px, 92vw); min-height: 570px; display: grid; grid-template-columns: 0.86fr 1.14fr; overflow: hidden; background: white; border: 1px solid rgba(218, 225, 235, 0.9); border-radius: 18px; box-shadow: 0 30px 70px rgba(35, 55, 84, 0.14); } +.activation-brand-panel { position: relative; overflow: hidden; display: flex; flex-direction: column; justify-content: space-between; padding: 42px 40px; color: white; background: #1769e0; } +.activation-brand-panel::before { content: ""; position: absolute; inset: 0; opacity: 0.18; background-image: radial-gradient(circle at 1px 1px, #fff 1px, transparent 0); background-size: 20px 20px; mask-image: linear-gradient(to bottom right, black, transparent 72%); } +.activation-brand-panel > * { position: relative; z-index: 1; } +.activation-kicker { display: flex; align-items: center; gap: 7px; width: max-content; padding: 7px 10px; border: 1px solid rgba(255,255,255,.24); border-radius: 6px; font-size: 12px; font-weight: 650; letter-spacing: .08em; } +.activation-visual { position: relative; width: 220px; height: 210px; margin: 5px auto -4px; display: grid; place-items: center; } +.visual-shield { width: 142px; height: 142px; display: grid; place-items: center; color: var(--blue); background: white; border-radius: 44% 44% 50% 50% / 34% 34% 62% 62%; box-shadow: 0 20px 50px rgba(8, 42, 98, 0.24); } +.visual-orbit { position: absolute; inset: 18px; border: 1px solid rgba(255,255,255,.25); border-radius: 50%; transform: rotate(-14deg); } +.orbit-two { inset: 2px 34px; transform: rotate(40deg); } +.visual-check { position: absolute; right: 28px; bottom: 29px; display: grid; place-items: center; width: 36px; height: 36px; color: #0a6b61; background: #72eadc; border: 5px solid var(--blue); border-radius: 50%; } +.activation-brand-panel h1 { margin: 0; font-size: 31px; letter-spacing: .02em; } +.activation-brand-panel p { margin: 8px 0 0; color: rgba(255,255,255,.72); font-size: 14px; } +.activation-features { display: flex; gap: 14px; padding-top: 20px; border-top: 1px solid rgba(255,255,255,.18); } +.activation-features span { display: flex; align-items: center; gap: 6px; color: rgba(255,255,255,.8); font-size: 11px; white-space: nowrap; } +.activation-form-panel { display: flex; flex-direction: column; justify-content: center; padding: 56px 68px; } +.eyebrow { color: var(--blue); font-family: Bahnschrift, "DIN Alternate", sans-serif; font-size: 11px; font-weight: 700; letter-spacing: .14em; } +.activation-heading h2 { margin: 12px 0 10px; color: #1d2635; font-size: 28px; line-height: 1.25; } +.activation-heading p { max-width: 470px; margin: 0 0 34px; color: #778195; font-size: 13px; line-height: 1.8; } +.field-label { display: block; margin-bottom: 9px; color: #404959; font-size: 13px; font-weight: 650; } +.activation-input { height: 54px; display: flex; align-items: center; gap: 11px; padding: 0 16px; color: #8190a6; background: #fbfcfe; border: 1px solid #dce3ec; border-radius: 9px; transition: border .18s, box-shadow .18s; } +.activation-input:focus-within { color: var(--blue); border-color: var(--blue); box-shadow: 0 0 0 4px rgba(23,105,224,.08); } +.activation-input.invalid { border-color: #e8a2a2; } +.activation-input input { width: 100%; border: 0; outline: 0; color: #253044; background: transparent; font-family: Bahnschrift, Consolas, monospace; font-size: 17px; letter-spacing: .055em; } +.activation-input input::placeholder { color: #aeb7c5; } +.activation-error { display: flex; align-items: flex-start; gap: 7px; margin-top: 10px; color: #c64747; font-size: 12px; line-height: 1.5; } +.activation-error svg { flex: 0 0 auto; margin-top: 1px; } +.primary-button { display: inline-flex; align-items: center; justify-content: center; gap: 8px; color: white; background: var(--blue); border-radius: 7px; font-weight: 650; cursor: pointer; transition: background .18s, transform .18s, box-shadow .18s; } +.primary-button:hover:not(:disabled) { background: var(--blue-deep); box-shadow: 0 8px 20px rgba(23,105,224,.2); transform: translateY(-1px); } +.activation-button { width: 100%; height: 48px; margin-top: 20px; } +.text-button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; color: var(--blue); background: transparent; cursor: pointer; } +.retry-button { margin: 12px auto 0; font-size: 12px; } +.activation-note { display: flex; align-items: flex-start; gap: 8px; margin-top: 28px; padding-top: 20px; color: #8a93a2; border-top: 1px solid #edf0f4; font-size: 11px; line-height: 1.6; } +.activation-note svg { flex: 0 0 auto; margin-top: 1px; } +.activation-footer { margin-top: 22px; color: #9aa4b2; font-size: 11px; } + +.workspace-shell { height: calc(100% - 48px); display: grid; grid-template-columns: 218px 1fr; } +.sidebar { display: flex; flex-direction: column; min-height: 0; padding: 20px 14px 16px; background: #f8fafc; border-right: 1px solid var(--line); } +.sidebar-profile { display: flex; align-items: center; gap: 11px; padding: 12px; background: white; border: 1px solid #e7ebf1; border-radius: 9px; } +.profile-mark { width: 36px; height: 36px; display: grid; place-items: center; color: #0b776a; background: #dff8f3; border-radius: 8px; } +.sidebar-profile div:last-child { min-width: 0; display: flex; flex-direction: column; gap: 3px; } +.sidebar-profile strong { font-size: 12px; } +.sidebar-profile span { overflow: hidden; color: #8b94a4; font-family: Bahnschrift, monospace; font-size: 10px; text-overflow: ellipsis; white-space: nowrap; } +.sidebar-navigation { display: flex; flex-direction: column; gap: 5px; margin-top: 24px; } +.sidebar-navigation button { height: 43px; display: grid; grid-template-columns: 22px 1fr 15px; align-items: center; gap: 9px; padding: 0 12px; color: #687386; background: transparent; border-radius: 7px; text-align: left; cursor: pointer; transition: background .16s, color .16s; } +.sidebar-navigation button:hover { color: #344155; background: #eef2f7; } +.sidebar-navigation button.active { color: var(--blue); background: #eaf2ff; font-weight: 650; } +.sidebar-navigation button svg:last-child { opacity: 0; transform: translateX(-3px); transition: opacity .16s, transform .16s; } +.sidebar-navigation button.active svg:last-child { opacity: 1; transform: translateX(0); } +.sidebar-bottom { margin-top: auto; display: flex; flex-direction: column; gap: 8px; padding: 0 7px; color: #99a2b0; font-size: 10px; } +.version-chip { width: max-content; padding: 4px 7px; color: #66748a; background: #e9eef4; border-radius: 4px; font-family: Bahnschrift, sans-serif; } + +.workspace-main, .detail-page { min-width: 0; min-height: 0; overflow: auto; padding: 28px 30px 30px; } +.update-banner { min-height: 58px; display: grid; grid-template-columns: 36px 1fr auto; align-items: center; gap: 12px; margin-bottom: 18px; padding: 10px 12px; color: #1555a9; background: #eaf3ff; border: 1px solid #cfe2ff; border-radius: 9px; } +.update-banner.force { color: #9b5620; background: #fff4e6; border-color: #f2d3aa; } +.update-banner-icon { width: 34px; height: 34px; display: grid; place-items: center; background: rgba(255,255,255,.72); border-radius: 7px; } +.update-banner div:nth-child(2) { display: flex; flex-direction: column; gap: 4px; } +.update-banner strong { font-size: 12px; } +.update-banner span { overflow: hidden; font-size: 11px; opacity: .76; text-overflow: ellipsis; white-space: nowrap; } +.update-banner button { display: flex; align-items: center; gap: 5px; padding: 8px 10px; color: inherit; background: white; border-radius: 6px; font-size: 11px; font-weight: 650; cursor: pointer; } +.workspace-header { display: flex; align-items: center; justify-content: space-between; gap: 40px; margin-bottom: 22px; } +.workspace-header h1, .detail-header h1 { margin: 8px 0 5px; color: #1d2635; font-size: 25px; line-height: 1.25; } +.workspace-header p, .detail-header p { margin: 0; color: #7c8696; font-size: 12px; } +.process-rail { display: flex; align-items: center; min-width: 390px; padding: 15px 18px; background: white; border: 1px solid var(--line); border-radius: 10px; } +.rail-step { display: flex; align-items: center; gap: 7px; color: #a0a8b4; white-space: nowrap; } +.rail-step span { width: 23px; height: 23px; display: grid; place-items: center; color: #8994a6; background: #eef1f5; border-radius: 50%; font-family: Bahnschrift, sans-serif; font-size: 10px; } +.rail-step b { font-size: 11px; font-weight: 550; } +.rail-step.active { color: #334055; } +.rail-step.active span { color: white; background: var(--blue); } +.rail-line { width: 34px; height: 2px; margin: 0 8px; background: #e4e8ee; transition: background .25s; } +.rail-line.active { background: var(--blue); } +.processor-layout { height: calc(100% - 105px); min-height: 570px; display: grid; grid-template-columns: minmax(0, 1fr) 306px; gap: 18px; } +.queue-card, .settings-card { background: white; border: 1px solid var(--line); border-radius: 11px; box-shadow: 0 4px 15px rgba(43, 59, 84, 0.035); } +.queue-card { min-height: 0; display: flex; flex-direction: column; overflow: hidden; } +.queue-toolbar { min-height: 64px; display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 0 18px; border-bottom: 1px solid #edf0f4; } +.queue-title { display: flex; align-items: baseline; gap: 9px; } +.queue-title h2, .settings-heading h2 { margin: 0; font-size: 14px; } +.queue-title span { color: #919aa8; font-size: 10px; } +.queue-actions { display: flex; gap: 7px; } +.secondary-button, .icon-button, .primary-quiet-button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 32px; padding: 0 10px; color: #526074; background: white; border: 1px solid #dfe5ed; border-radius: 6px; font-size: 11px; cursor: pointer; transition: color .16s, border .16s, background .16s; } +.secondary-button:hover:not(:disabled), .icon-button:hover:not(:disabled) { color: var(--blue); border-color: #aecaf1; background: #f8fbff; } +.icon-button { width: 32px; padding: 0; } +.drop-zone { flex: 1; margin: 16px; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 390px; background: #fbfcfe; border: 1px dashed #cfd8e5; border-radius: 10px; cursor: pointer; transition: border .18s, background .18s, transform .18s; } +.drop-zone:hover, .drop-zone.active { background: #f4f8ff; border-color: var(--blue); } +.drop-visual { position: relative; width: 104px; height: 88px; margin-bottom: 18px; } +.file-tile { position: absolute; width: 58px; height: 66px; display: grid; place-items: center; border-radius: 9px; } +.tile-back { left: 14px; top: 4px; color: #7ea9e5; background: #e5f0ff; transform: rotate(-9deg); } +.tile-front { right: 10px; bottom: 2px; color: white; background: var(--blue); box-shadow: 0 12px 26px rgba(23,105,224,.18); transform: rotate(5deg); } +.drop-zone h3 { margin: 0 0 8px; font-size: 15px; } +.drop-zone p { margin: 0 0 18px; color: #929baa; font-size: 11px; } +.primary-quiet-button { color: var(--blue); background: #edf4ff; border-color: transparent; font-weight: 650; } +.queue-table { flex: 1; min-height: 0; display: flex; flex-direction: column; } +.queue-table-head, .queue-row { display: grid; grid-template-columns: minmax(250px, 1fr) 100px 82px 110px 32px; align-items: center; gap: 10px; } +.queue-table-head { min-height: 39px; padding: 0 18px; color: #98a1af; background: #fafbfd; border-bottom: 1px solid #eef1f5; font-size: 10px; } +.queue-rows { flex: 1; min-height: 0; overflow: auto; } +.queue-row { min-height: 64px; padding: 8px 18px; border-bottom: 1px solid #f0f2f5; transition: background .15s; } +.queue-row:hover { background: #fafcff; } +.queue-row.is-processing { background: #f7faff; } +.file-cell { min-width: 0; display: flex; align-items: center; gap: 10px; } +.file-icon { flex: 0 0 auto; width: 34px; height: 34px; display: grid; place-items: center; color: var(--blue); background: #eaf3ff; border-radius: 7px; } +.file-cell > div:last-child { min-width: 0; display: flex; flex-direction: column; gap: 4px; } +.file-cell strong, .file-cell span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.file-cell strong { color: #374154; font-size: 11px; font-weight: 650; } +.file-cell span { color: #9aa3b1; font-size: 9px; } +.data-cell { color: #747f90; font-family: Bahnschrift, "Microsoft YaHei UI", sans-serif; font-size: 10px; } +.status-cell { min-width: 0; display: flex; align-items: center; gap: 5px; color: #8792a3; font-size: 10px; } +.status-cell span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.status-cell.processing { color: var(--blue); } +.status-cell.completed { color: #149173; } +.status-cell.failed { color: var(--danger); } +.row-action { width: 28px; height: 28px; display: grid; place-items: center; color: #919baa; background: transparent; border-radius: 5px; cursor: pointer; } +.row-action:hover:not(:disabled) { color: var(--blue); background: #edf4ff; } +.progress-dock { padding: 14px 18px; border-top: 1px solid #e8ecf2; background: #fbfcfe; } +.progress-meta { display: flex; align-items: center; justify-content: space-between; margin-bottom: 9px; } +.progress-meta div { display: flex; align-items: baseline; gap: 8px; } +.progress-meta strong { font-size: 11px; } +.progress-meta span { color: #929baa; font-family: Bahnschrift, sans-serif; font-size: 10px; } +.progress-meta b { color: var(--blue); font-family: Bahnschrift, sans-serif; font-size: 11px; } +.progress-track { height: 5px; overflow: hidden; background: #e7ebf1; border-radius: 3px; } +.progress-track span { display: block; height: 100%; background: var(--blue); border-radius: inherit; transition: width .2s ease; } + +.settings-card { display: flex; flex-direction: column; padding: 18px; overflow: auto; } +.settings-heading { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; } +.settings-heading svg { color: var(--blue); } +.setting-group { padding: 16px 0; border-bottom: 1px solid #edf0f4; } +.setting-group > label, .setting-label-row label { display: block; margin-bottom: 9px; color: #4c5667; font-size: 11px; font-weight: 650; } +.path-picker { width: 100%; height: 39px; display: grid; grid-template-columns: 18px 1fr 16px; align-items: center; gap: 7px; padding: 0 10px; color: #566277; background: #f9fafc; border: 1px solid #e1e6ed; border-radius: 7px; cursor: pointer; } +.path-picker span { overflow: hidden; text-align: left; text-overflow: ellipsis; white-space: nowrap; font-size: 10px; } +.path-picker svg:last-child { color: #a2aab7; } +.check-row { position: relative; display: flex !important; align-items: center; gap: 7px; margin: 10px 0 0 !important; color: #758092 !important; font-size: 10px !important; font-weight: 400 !important; cursor: pointer; } +.check-row input { position: absolute; opacity: 0; } +.custom-check { width: 17px; height: 17px; display: grid; place-items: center; color: transparent; background: white; border: 1px solid #cfd7e2; border-radius: 4px; } +.check-row input:checked + .custom-check { color: white; background: var(--blue); border-color: var(--blue); } +.format-switch { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; } +.format-switch button { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; padding: 11px; color: #697488; background: #fafbfd; border: 1px solid #e2e7ee; border-radius: 7px; cursor: pointer; } +.format-switch button.active { color: var(--blue); background: #f1f6ff; border-color: #9fc2f3; box-shadow: inset 0 0 0 1px rgba(23,105,224,.08); } +.format-switch b { font-family: Bahnschrift, Consolas, monospace; font-size: 12px; } +.format-switch span { font-size: 9px; opacity: .72; } +.setting-label-row { display: flex; align-items: center; justify-content: space-between; } +.setting-label-row label { margin: 0; } +.junk-size-input { display: flex; align-items: center; overflow: hidden; height: 28px; background: #f8fafc; border: 1px solid #dde4ed; border-radius: 6px; } +.junk-size-input input { width: 58px; height: 100%; padding: 0 6px; color: var(--blue); background: transparent; border: 0; outline: 0; font-family: Bahnschrift, sans-serif; font-size: 11px; text-align: right; } +.junk-size-input span { padding-right: 7px; color: #8993a2; font-size: 9px; } +.range-control { width: 100%; height: 4px; margin: 16px 0 7px; accent-color: var(--blue); cursor: pointer; } +.range-labels { display: flex; justify-content: space-between; color: #a0a8b5; font-family: Bahnschrift, sans-serif; font-size: 8px; } +.setting-help { margin: 10px 0 0; color: #949dab; font-size: 9px; line-height: 1.6; } +.algorithm-note { margin-top: 15px; padding: 12px; color: #34605a; background: #edf9f6; border: 1px solid #d7efe9; border-radius: 8px; } +.algorithm-note div { display: flex; align-items: center; gap: 7px; } +.algorithm-note strong { font-size: 10px; } +.algorithm-note p { margin: 7px 0 0; color: #6e8e89; font-size: 9px; line-height: 1.55; } +.start-area { margin-top: auto; padding-top: 18px; } +.start-button, .cancel-button { width: 100%; height: 43px; } +.cancel-button { display: flex; align-items: center; justify-content: center; gap: 8px; color: #b44444; background: #fff2f2; border: 1px solid #efcaca; border-radius: 7px; font-weight: 650; cursor: pointer; } +.start-area > span { display: block; margin-top: 9px; color: #9aa3b0; font-size: 9px; text-align: center; } + +.detail-page { padding: 40px 48px; } +.detail-header { margin-bottom: 24px; } +.license-hero-card { display: grid; grid-template-columns: 72px 1fr auto; align-items: center; gap: 20px; padding: 28px; color: white; background-color: #1769e0; background-image: radial-gradient(circle at 1px 1px, rgba(255,255,255,.16) 1px, transparent 0); background-size: 22px 22px; border-radius: 12px; box-shadow: 0 18px 40px rgba(23,105,224,.18); } +.license-shield { width: 68px; height: 68px; display: grid; place-items: center; color: var(--blue); background: white; border-radius: 18px; } +.license-status { display: flex; align-items: center; gap: 7px; color: rgba(255,255,255,.76); font-size: 10px; } +.license-status span { width: 7px; height: 7px; background: #70ead9; border-radius: 50%; } +.license-hero-copy h2 { margin: 9px 0 7px; font-family: Bahnschrift, Consolas, monospace; font-size: 22px; letter-spacing: .04em; } +.license-hero-copy p { margin: 0; color: rgba(255,255,255,.72); font-size: 11px; } +.license-expiry { display: flex; flex-direction: column; align-items: flex-end; gap: 7px; padding-left: 30px; border-left: 1px solid rgba(255,255,255,.2); } +.license-expiry span { color: rgba(255,255,255,.64); font-size: 10px; } +.license-expiry strong { font-size: 14px; } +.detail-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: 18px; } +.detail-card { display: flex; flex-direction: column; min-height: 132px; padding: 20px; background: white; border: 1px solid var(--line); border-radius: 10px; } +.detail-card span { color: #8993a2; font-size: 10px; } +.detail-card strong { margin: 15px 0 7px; font-size: 18px; } +.detail-card small { margin-top: auto; color: #9ba4b2; font-size: 9px; } +.danger-zone { display: flex; align-items: center; justify-content: space-between; margin-top: 18px; padding: 20px; background: white; border: 1px solid #f0dede; border-radius: 10px; } +.danger-zone strong { font-size: 12px; } +.danger-zone p { margin: 6px 0 0; color: #929aa7; font-size: 10px; } +.danger-outline-button { display: flex; align-items: center; gap: 6px; padding: 9px 12px; color: #c14949; background: white; border: 1px solid #e7baba; border-radius: 6px; font-size: 10px; cursor: pointer; } +.about-card { display: grid; grid-template-columns: 64px 1fr auto; align-items: center; gap: 18px; padding: 25px; background: white; border: 1px solid var(--line); border-radius: 11px; } +.about-mark { width: 62px; height: 62px; display: grid; place-items: center; color: white; background: var(--blue); border-radius: 16px; } +.about-copy h2 { margin: 0 0 5px; font-size: 20px; } +.about-copy p { margin: 0 0 8px; color: #7f8999; font-size: 11px; } +.about-copy span { color: #a0a8b5; font-family: Bahnschrift, sans-serif; font-size: 9px; } +.release-card { display: flex; align-items: center; justify-content: space-between; margin-top: 14px; padding: 18px; background: #edf4ff; border: 1px solid #d4e4fa; border-radius: 10px; } +.release-card > div { display: flex; align-items: flex-start; gap: 12px; color: var(--blue); } +.release-card strong { color: #2e3c51; font-size: 12px; } +.release-card p { margin: 5px 0 0; color: #748095; font-size: 10px; } +.release-card button { padding: 9px 14px; } +.about-features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: 14px; } +.about-features > div { min-height: 150px; display: flex; flex-direction: column; padding: 20px; color: var(--blue); background: white; border: 1px solid var(--line); border-radius: 10px; } +.about-features strong { margin-top: 20px; color: #313c4f; font-size: 12px; } +.about-features p { margin: 7px 0 0; color: #8d96a4; font-size: 10px; line-height: 1.6; } + +.drop-overlay { position: fixed; z-index: 50; inset: 48px 0 0; display: grid; place-items: center; padding: 32px; background: rgba(238, 245, 254, .9); backdrop-filter: blur(6px); } +.drop-overlay > div { width: min(620px, 70vw); height: 310px; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--blue); background: white; border: 2px dashed #81adea; border-radius: 16px; box-shadow: var(--shadow); } +.drop-overlay strong { margin-top: 18px; color: #2f3b4e; font-size: 18px; } +.drop-overlay span { margin-top: 8px; color: #8c96a5; font-size: 11px; } +.toast-message { position: fixed; z-index: 80; left: 50%; bottom: 28px; display: flex; align-items: center; gap: 8px; max-width: 520px; padding: 11px 15px; color: #2d384a; background: white; border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 14px 34px rgba(36, 51, 74, .16); font-size: 11px; transform: translateX(-50%); } +.toast-message.success svg { color: #159271; } +.toast-message.error svg { color: var(--danger); } +.toast-message.info svg { color: var(--blue); } +.toast-enter-active, .toast-leave-active { transition: opacity .2s, transform .2s; } +.toast-enter-from, .toast-leave-to { opacity: 0; transform: translate(-50%, 10px); } + +@media (max-width: 1220px) { + .workspace-shell { grid-template-columns: 196px 1fr; } + .workspace-main { padding: 24px 22px; } + .process-rail { min-width: 350px; } + .processor-layout { grid-template-columns: minmax(0, 1fr) 286px; } + .activation-form-panel { padding: 50px 48px; } +} + +/* 保证小屏笔记本在允许的最小窗口高度下仍能看到核心处理操作。 */ +@media (max-height: 760px) { + .workspace-main { padding-top: 18px; padding-bottom: 18px; } + .workspace-header { margin-bottom: 14px; } + .processor-layout { height: calc(100% - 91px); min-height: 0; } + .settings-card { padding: 14px; } + .setting-group { padding: 12px 0; } + .algorithm-note { margin-top: 10px; padding: 10px; } + .start-area { padding-top: 12px; } +} + +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; scroll-behavior: auto !important; transition-duration: .01ms !important; } +} diff --git a/src/shared/types.ts b/src/shared/types.ts new file mode 100644 index 0000000..35aadc7 --- /dev/null +++ b/src/shared/types.ts @@ -0,0 +1,90 @@ +export type OutputFormat = 'file' | 'file-jpg' +export type ImageStatus = 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled' + +export interface ImageFileItem { + id: string + path: string + name: string + size: number + width: number | null + height: number | null + status: ImageStatus + outputPath?: string + error?: string +} + +export interface ProcessOptions { + paths: string[] + useSourceDirectory: boolean + outputDirectory?: string + outputFormat: OutputFormat + junkSizeMb: number +} + +export interface ProcessProgress { + current: number + total: number + percent: number + item: ImageFileItem + cancelled: boolean +} + +export interface ProcessSummary { + total: number + completed: number + failed: number + cancelled: boolean +} + +export interface VersionInfo { + updateAvailable: boolean + latestVersion?: string + releaseNotes?: string + downloadUrl?: string + enforce: boolean +} + +export interface LicenseSession { + token?: string + licenseCodeMask: string + deviceMask: string + expiresAt?: string + maxDevices: number + version?: VersionInfo +} + +export type LicenseStatus = 'checking' | 'unlicensed' | 'active' | 'invalid' | 'network-error' + +export interface LicenseViewState { + status: LicenseStatus + message: string + offline: boolean + session?: LicenseSession + version?: VersionInfo +} + +export interface AppInfo { + name: string + version: string + platform: string + deviceName: string +} + +export interface DesktopBridge { + getAppInfo(): Promise + getLicenseState(): Promise + activate(activationCode: string): Promise + validateLicense(): Promise + clearLicense(): Promise + checkVersion(): Promise + downloadUpdate(downloadUrl: string, latestVersion?: string): Promise + selectImages(): Promise + selectFolder(): Promise + selectOutputDirectory(): Promise + pathsForFiles(files: File[]): string[] + inspectImages(paths: string[]): Promise + processImages(options: ProcessOptions): Promise + cancelProcessing(): Promise + revealItem(filePath: string): Promise + onProcessProgress(callback: (progress: ProcessProgress) => void): () => void +} diff --git a/tsconfig.electron.json b/tsconfig.electron.json new file mode 100644 index 0000000..746466f --- /dev/null +++ b/tsconfig.electron.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "CommonJS", + "moduleResolution": "Node", + "strict": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "outDir": "dist-electron", + "rootDir": ".", + "types": ["node", "electron"], + "skipLibCheck": true + }, + "include": ["electron/**/*.ts", "src/shared/**/*.ts"], + "exclude": ["electron/**/*.spec.ts"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..a2ffeb6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.renderer.json" }, + { "path": "./tsconfig.electron.json" } + ] +} diff --git a/tsconfig.renderer.json b/tsconfig.renderer.json new file mode 100644 index 0000000..ad83627 --- /dev/null +++ b/tsconfig.renderer.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "jsx": "preserve", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "baseUrl": ".", + "paths": { + "@/*": ["src/renderer/*"], + "@shared/*": ["src/shared/*"] + }, + "skipLibCheck": true + }, + "include": ["src/renderer/**/*.ts", "src/renderer/**/*.vue", "src/shared/**/*.ts", "src/env.d.ts"] +} diff --git a/vite.config.mjs b/vite.config.mjs new file mode 100644 index 0000000..4021806 --- /dev/null +++ b/vite.config.mjs @@ -0,0 +1,25 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const currentDirectory = path.dirname(fileURLToPath(import.meta.url)) + +export default defineConfig({ + plugins: [vue()], + resolve: { + alias: { + '@': path.resolve(currentDirectory, 'src/renderer'), + '@shared': path.resolve(currentDirectory, 'src/shared'), + }, + }, + base: './', + build: { + outDir: 'dist', + emptyOutDir: true, + }, + test: { + include: ['electron/**/*.spec.ts'], + exclude: ['node_modules/**', 'dist/**', 'dist-electron/**', 'release/**'], + }, +})