commit b56c63e166e70e8d97419b975d495b4e12e23298 Author: 黄志军 <851516902@qq.com> Date: Fri May 15 16:35:31 2026 +0800 代码初始化 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7b693df --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules +out +release +dist +.DS_Store +*.log diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/MyReader.iml b/.idea/MyReader.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/MyReader.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..e9710cf --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..07de7d6 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..623e284 --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# Huangzhijun's Reader + +本地 Markdown 阅读与编辑(Electron + Vite + React + CodeMirror 6)。侧重「长文阅读体验」与「轻量编辑」:多标签、会话恢复、侧栏文件树与大纲、阅读/编辑/分栏三模式、外观与行距可调。 + +## 设计思路 + +1. **进程与数据** + 主进程负责文件系统对话框、读写目录、路径解析与窗口生命周期;预加载脚本通过 `contextBridge` 暴露受限 API,渲染进程不开启 `nodeIntegration`,在隔离前提下使用本地文件能力。 + +2. **渲染与 Markdown** + 使用 `markdown-it` + 插件(表格、Mermaid 围栏等)生成 HTML,再经 DOMPurify 白名单消毒后注入预览。相对路径图片在渲染阶段结合当前文件路径解析为 `file://` URL;开发环境下页面为 `http(s)` 源时,通过主窗口 **`webSecurity: false`** 允许从页面加载本地 `file://` 图片(典型 Electron 本地阅读器权衡)。 + +3. **阅读体验** + 背景与字体通过 `html` 上的 `data-bg` / `data-font` 切换 CSS 变量,预览区单独使用 `--preview-bg`、`--font-preview` 等,与侧栏/工具栏解耦。阅读行距使用 `--preview-line-height`,与字体选择独立。Mermaid 图在源码中写入 `data-mermaid-src`,便于分栏宽度变化后恢复文本并重绘。 + +4. **分栏同步** + 编辑器与预览共享文档字符串;预览 DOM 为块级元素打上源行号,用于大纲跳转与分栏滚动对齐。 + +5. **持久化** + 标签内容与未保存状态、当前背景/字体等写入 `localStorage`(会话键 `myreader-session-v1`);打开过的 Markdown 路径记入「历史」列表,与真实文件删除无关。 + +## 使用步骤(简述) + +1. **安装依赖**:在项目根目录执行 `npm install`。 +2. **开发运行**:`npm run dev`,在 Electron 窗口内使用。 +3. **打开文档**:工具栏「打开」、侧栏「打开文件夹」后点击 `.md` 文件,或从历史记录点选。 +4. **视图**:工具栏「视图」或使用 `Ctrl+E` 在 **编辑 / 阅读 / 分栏** 间切换。 +5. **外观**:工具栏右侧 **阅读行距**、**字体**、**背景**(含「Kindle 纸感」等)按需调整。 +6. **图片**:编辑模式下用工具栏插入本地图片;保存路径为 `file://` 或相对路径时,阅读/分栏预览会按上文规则解析显示。 +7. **图表**:在 Markdown 中使用 ` ```mermaid ` 围栏编写 Mermaid 语法即可在预览中渲染。 +8. **构建与打包**:`npm run build` 输出到 `out/`;`npm run dist` 构建并生成 Windows 安装包至 `release/`。 + +## 脚本 + +| 命令 | 说明 | +|------|------| +| `npm run dev` | 开发调试 | +| `npm run build` | 构建到 `out/` | +| `npm run typecheck` | TypeScript 检查 | +| `npm run dist` | 构建并打 Windows 安装包(`release/`) | + +## 快捷键(与应用菜单一致) + +- `Ctrl+O` 打开,`Ctrl+S` 保存,`Ctrl+Shift+S` 另存为 +- `Ctrl+T` 新标签,`Ctrl+W` 关闭标签 +- `Ctrl+Tab` / `Ctrl+Shift+Tab` 切换标签 +- `Ctrl+E`:在 **编辑 / 阅读 / 分栏** 三种视图间循环切换 + +侧栏可隐藏、可拖动右边缘调整宽度;阅读模式下可拖动预览区右缘调整正文最大宽度。编辑、分栏模式下顶部有 **Markdown 格式工具栏**。侧栏文件列表 **右键**:重命名(文件/文件夹)、删除(仅文件)。 + +## 技术栈摘要 + +Electron 35、electron-vite、React 19、CodeMirror 6、markdown-it、highlight.js、DOMPurify、mermaid。 + +--- + +仓库 npm 包名仍为 `myreader`;安装后显示名与窗口标题为 **Huangzhijun's Reader**。 diff --git a/electron.vite.config.ts b/electron.vite.config.ts new file mode 100644 index 0000000..60ccbe9 --- /dev/null +++ b/electron.vite.config.ts @@ -0,0 +1,29 @@ +import { resolve } from 'node:path' +import { defineConfig, externalizeDepsPlugin } from 'electron-vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + main: { + plugins: [externalizeDepsPlugin()], + build: { + rollupOptions: { + input: { + index: resolve(__dirname, 'electron/main.ts') + } + } + } + }, + preload: { + plugins: [externalizeDepsPlugin()], + build: { + rollupOptions: { + input: { + index: resolve(__dirname, 'electron/preload.ts') + } + } + } + }, + renderer: { + plugins: [react()] + } +}) diff --git a/electron/ipc-types.ts b/electron/ipc-types.ts new file mode 100644 index 0000000..92b5ed9 --- /dev/null +++ b/electron/ipc-types.ts @@ -0,0 +1,33 @@ +export type DirEntry = { + name: string + path: string + kind: 'file' | 'dir' +} + +export type ListDirResult = { + entries: DirEntry[] + error?: string +} + +export type OpenFileResult = { + canceled: boolean + path?: string + content?: string +} + +export type SaveDialogResult = { + canceled: boolean + path?: string +} + +export type OpenFolderResult = { + canceled: boolean + path?: string +} + +/** `url` 为可写入 Markdown 的 `file://` 绝对地址(已编码)。 */ +export type OpenImageResult = { + canceled: boolean + url?: string + path?: string +} diff --git a/electron/main.ts b/electron/main.ts new file mode 100644 index 0000000..d932ec9 --- /dev/null +++ b/electron/main.ts @@ -0,0 +1,368 @@ +import { existsSync } from 'node:fs' +import { readdir, rename, readFile, writeFile, unlink } from 'node:fs/promises' +import { dirname, join, resolve, normalize, isAbsolute } from 'node:path' +import { pathToFileURL, fileURLToPath } from 'node:url' +import { + app, + BrowserWindow, + dialog, + ipcMain, + Menu, + nativeImage, + shell, + type MenuItemConstructorOptions, + type NativeImage +} from 'electron' +import type { + DirEntry, + ListDirResult, + OpenFileResult, + OpenFolderResult, + OpenImageResult, + SaveDialogResult +} from './ipc-types.js' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +const MD_EXT = new Set(['.md', '.markdown', '.mdown', '.mkd']) + +function getPreloadPath(): string { + const fromMainDir = join(__dirname, '..', 'preload') + const fromAppRoot = join(app.getAppPath(), 'out', 'preload') + const candidates = ['index.mjs', 'index.cjs', 'index.js'] + for (const base of [fromMainDir, fromAppRoot]) { + for (const name of candidates) { + const p = resolve(base, name) + if (existsSync(p)) return p + } + } + return resolve(fromAppRoot, 'index.mjs') +} + +function getRendererIndexHtml(): string { + const fromMain = join(__dirname, '..', 'renderer', 'index.html') + if (existsSync(fromMain)) return fromMain + return join(app.getAppPath(), 'out', 'renderer', 'index.html') +} + +function resolveAppIconPath(): string | undefined { + const candidates = [ + join(__dirname, '../../resources/app-icon.png'), + join(app.getAppPath(), 'resources', 'app-icon.png'), + join(process.cwd(), 'resources', 'app-icon.png') + ] + for (const p of candidates) { + if (existsSync(p)) return p + } + return undefined +} + +function isMarkdownFile(name: string): boolean { + const lower = name.toLowerCase() + const dot = lower.lastIndexOf('.') + if (dot < 0) return false + return MD_EXT.has(lower.slice(dot)) +} + +/** 将 Markdown 内链(相对/绝对/file://)解析为本地绝对路径;外链原样返回。 */ +function resolveMarkdownLinkHref(baseFilePath: string, href: string): string { + let raw = href.trim() + const hashIdx = raw.indexOf('#') + if (hashIdx >= 0) raw = raw.slice(0, hashIdx) + const queryIdx = raw.indexOf('?') + if (queryIdx >= 0) raw = raw.slice(0, queryIdx) + raw = raw.trim() + if (!raw) return '' + if (/^https?:\/\//i.test(raw) || /^mailto:/i.test(raw) || /^tel:/i.test(raw)) return raw + if (raw.startsWith('file://')) { + try { + return normalize(fileURLToPath(raw)) + } catch { + return '' + } + } + let decoded = raw + try { + decoded = decodeURIComponent(raw) + } catch { + decoded = raw + } + if (isAbsolute(decoded)) return normalize(decoded) + return normalize(resolve(dirname(baseFilePath), decoded)) +} + +ipcMain.handle( + 'myreader:resolve-relative-path', + (_evt, baseFilePath: string, href: string): string => { + if (typeof baseFilePath !== 'string' || typeof href !== 'string') return '' + if (!baseFilePath.trim()) return '' + return resolveMarkdownLinkHref(baseFilePath, href) + } +) + +ipcMain.handle('myreader:open-external', async (_evt, url: string): Promise => { + if (typeof url !== 'string') return + const u = url.trim() + if (/^https?:\/\//i.test(u) || /^mailto:/i.test(u) || /^tel:/i.test(u)) { + await shell.openExternal(u) + } +}) + +async function listDirectoryImpl(dirPath: string): Promise { + const normalized = normalize(dirPath) + try { + const dirents = await readdir(normalized, { withFileTypes: true }) + const entries: DirEntry[] = [] + for (const d of dirents) { + if (d.name.startsWith('.')) continue + const full = join(normalized, d.name) + if (d.isDirectory()) { + entries.push({ name: d.name, path: full, kind: 'dir' }) + } else if (d.isFile() && isMarkdownFile(d.name)) { + entries.push({ name: d.name, path: full, kind: 'file' }) + } + } + entries.sort((a, b) => { + if (a.kind !== b.kind) return a.kind === 'dir' ? -1 : 1 + return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }) + }) + return { entries } + } catch (e) { + const msg = e instanceof Error ? e.message : String(e) + return { entries: [], error: msg } + } +} + +function sendMenu(win: BrowserWindow | null, action: string): void { + const w = win ?? BrowserWindow.getFocusedWindow() + w?.webContents.send('myreader:menu', action) +} + +function buildMenu(): Menu { + const template: MenuItemConstructorOptions[] = [ + { + label: '文件', + submenu: [ + { label: '新建标签', accelerator: 'CmdOrCtrl+T', click: () => sendMenu(null, 'tab-new') }, + { label: '打开…', accelerator: 'CmdOrCtrl+O', click: () => sendMenu(null, 'file-open') }, + { label: '保存', accelerator: 'CmdOrCtrl+S', click: () => sendMenu(null, 'file-save') }, + { label: '另存为…', accelerator: 'CmdOrCtrl+Shift+S', click: () => sendMenu(null, 'file-save-as') }, + { type: 'separator' }, + { label: '关闭标签', accelerator: 'CmdOrCtrl+W', click: () => sendMenu(null, 'tab-close') }, + { type: 'separator' }, + { label: '退出', accelerator: process.platform === 'darwin' ? 'Cmd+Q' : 'Alt+F4', role: 'quit' } + ] + }, + { + label: '编辑', + submenu: [ + { label: '撤销', accelerator: 'CmdOrCtrl+Z', role: 'undo' }, + { label: '重做', accelerator: process.platform === 'darwin' ? 'Cmd+Shift+Z' : 'Ctrl+Y', role: 'redo' }, + { type: 'separator' }, + { label: '剪切', accelerator: 'CmdOrCtrl+X', role: 'cut' }, + { label: '复制', accelerator: 'CmdOrCtrl+C', role: 'copy' }, + { label: '粘贴', accelerator: 'CmdOrCtrl+V', role: 'paste' }, + { label: '全选', accelerator: 'CmdOrCtrl+A', role: 'selectAll' } + ] + }, + { + label: '视图', + submenu: [ + { label: '切换视图模式', accelerator: 'CmdOrCtrl+E', click: () => sendMenu(null, 'toggle-read') }, + { label: '下一个标签', accelerator: 'Ctrl+Tab', click: () => sendMenu(null, 'tab-next') }, + { label: '上一个标签', accelerator: 'Ctrl+Shift+Tab', click: () => sendMenu(null, 'tab-prev') } + ] + }, + { + label: '帮助', + submenu: [{ label: "关于 Huangzhijun's Reader", click: () => sendMenu(null, 'help-about') }] + } + ] + return Menu.buildFromTemplate(template) +} + +function createWindow(): BrowserWindow { + const preloadPath = getPreloadPath() + const iconPath = resolveAppIconPath() + let icon: NativeImage | undefined + if (iconPath) { + try { + icon = nativeImage.createFromPath(iconPath) + if (icon.isEmpty()) icon = undefined + } catch { + icon = undefined + } + } + const win = new BrowserWindow({ + width: 1200, + height: 800, + minWidth: 800, + minHeight: 560, + title: "Huangzhijun's Reader", + ...(icon ? { icon } : {}), + webPreferences: { + preload: preloadPath, + contextIsolation: true, + sandbox: false, + nodeIntegration: false, + webSecurity: false + } + }) + + win.on('close', (e) => { + const w = win as BrowserWindow & { __myreaderForceClose?: boolean } + if (w.__myreaderForceClose) return + e.preventDefault() + win.webContents.send('myreader:request-close') + }) + + if (process.env.ELECTRON_RENDERER_URL) { + void win.loadURL(process.env.ELECTRON_RENDERER_URL) + } else { + void win.loadFile(getRendererIndexHtml()) + } + return win +} + +ipcMain.handle('myreader:open-file-dialog', async (): Promise => { + const win = BrowserWindow.getFocusedWindow() + const { canceled, filePaths } = win + ? await dialog.showOpenDialog(win, { + properties: ['openFile'], + filters: [{ name: 'Markdown', extensions: ['md', 'markdown', 'mdown', 'mkd', 'txt'] }] + }) + : await dialog.showOpenDialog({ + properties: ['openFile'], + filters: [{ name: 'Markdown', extensions: ['md', 'markdown', 'mdown', 'mkd', 'txt'] }] + }) + if (canceled || !filePaths?.[0]) return { canceled: true } + const path = filePaths[0] + const content = await readFile(path, 'utf8') + return { canceled: false, path, content } +}) + +ipcMain.handle('myreader:open-folder-dialog', async (): Promise => { + const win = BrowserWindow.getFocusedWindow() + const opts = { properties: ['openDirectory' as const] } + const { canceled, filePaths } = win + ? await dialog.showOpenDialog(win, opts) + : await dialog.showOpenDialog(opts) + if (canceled || !filePaths?.[0]) return { canceled: true } + return { canceled: false, path: filePaths[0] } +}) + +ipcMain.handle('myreader:open-image-dialog', async (event): Promise => { + const win = + BrowserWindow.fromWebContents(event.sender) ?? BrowserWindow.getFocusedWindow() + const opts = { + properties: ['openFile' as const], + filters: [ + { + name: '图片', + extensions: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp', 'ico', 'avif'] + } + ] + } + if (win) { + win.focus() + win.show() + } + const { canceled, filePaths } = win + ? await dialog.showOpenDialog(win, opts) + : await dialog.showOpenDialog(opts) + if (canceled || !filePaths?.[0]) return { canceled: true } + const path = filePaths[0] + return { canceled: false, path, url: pathToFileURL(path).href } +}) + +ipcMain.handle( + 'myreader:save-dialog', + async (_evt, defaultPath?: string): Promise => { + const win = BrowserWindow.getFocusedWindow() + const { canceled, filePath } = win + ? await dialog.showSaveDialog(win, { + defaultPath, + filters: [{ name: 'Markdown', extensions: ['md'] }] + }) + : await dialog.showSaveDialog({ + defaultPath, + filters: [{ name: 'Markdown', extensions: ['md'] }] + }) + if (canceled || !filePath) return { canceled: true } + return { canceled: false, path: filePath } + } +) + +ipcMain.handle('myreader:read-file', async (_evt, filePath: string): Promise => { + return readFile(filePath, 'utf8') +}) + +ipcMain.handle( + 'myreader:write-file', + async (_evt, filePath: string, content: string): Promise => { + await writeFile(filePath, content, 'utf8') + } +) + +ipcMain.handle('myreader:list-directory', async (_evt, dirPath: string): Promise => { + return listDirectoryImpl(dirPath) +}) + +ipcMain.handle('myreader:parent-directory', (_evt, dirPath: string): string => { + return dirname(dirPath) +}) + +ipcMain.handle('myreader:default-directory', async (): Promise => { + return app.getPath('documents') +}) + +ipcMain.handle('myreader:delete-file', async (_evt, filePath: string): Promise => { + if (typeof filePath !== 'string' || filePath.length === 0) { + throw new Error('Invalid path') + } + await unlink(filePath) +}) + +ipcMain.handle( + 'myreader:rename-path', + async (_evt, oldPath: string, newName: string): Promise<{ newPath: string }> => { + if (typeof oldPath !== 'string' || typeof newName !== 'string') { + throw new Error('Invalid arguments') + } + const clean = newName.replace(/[/\\]/g, '').trim() + if (!clean) { + throw new Error('Empty name') + } + const parent = dirname(oldPath) + const newPath = join(parent, clean) + if (normalize(newPath) === normalize(oldPath)) { + return { newPath: oldPath } + } + await rename(oldPath, newPath) + return { newPath } + } +) + +ipcMain.on('myreader:allow-close', (event) => { + const win = BrowserWindow.fromWebContents(event.sender) + if (!win) return + ;(win as BrowserWindow & { __myreaderForceClose?: boolean }).__myreaderForceClose = true + win.close() +}) + +app.whenReady().then(() => { + Menu.setApplicationMenu(buildMenu()) + createWindow() + app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } + }) +}) + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit() + } +}) diff --git a/electron/preload.ts b/electron/preload.ts new file mode 100644 index 0000000..d83bf19 --- /dev/null +++ b/electron/preload.ts @@ -0,0 +1,74 @@ +import { contextBridge, ipcRenderer } from 'electron' +import type { + ListDirResult, + OpenFileResult, + OpenFolderResult, + OpenImageResult, + SaveDialogResult +} from './ipc-types.js' + +export interface MyReaderApi { + openFileDialog: () => Promise + openFolderDialog: () => Promise + openImageDialog: () => Promise + saveFileDialog: (defaultPath?: string) => Promise + readFile: (filePath: string) => Promise + writeFile: (filePath: string, content: string) => Promise + listDirectory: (dirPath: string) => Promise + parentDirectory: (dirPath: string) => Promise + /** 相对当前 Markdown 文件解析内链 href → 绝对路径(外链原样返回) */ + resolveRelativePath: (baseFilePath: string, href: string) => Promise + openExternal: (url: string) => Promise + defaultDirectory: () => Promise + deleteFile: (filePath: string) => Promise + renamePath: (oldPath: string, newName: string) => Promise<{ newPath: string }> + allowClose: () => void + onRequestClose: (handler: () => void) => () => void + onMenuAction: (handler: (action: string) => void) => () => void +} + +const api: MyReaderApi = { + openFileDialog: () => ipcRenderer.invoke('myreader:open-file-dialog'), + openFolderDialog: () => ipcRenderer.invoke('myreader:open-folder-dialog'), + openImageDialog: () => ipcRenderer.invoke('myreader:open-image-dialog'), + saveFileDialog: (defaultPath?: string) => ipcRenderer.invoke('myreader:save-dialog', defaultPath), + readFile: (filePath: string) => ipcRenderer.invoke('myreader:read-file', filePath), + writeFile: (filePath: string, content: string) => + ipcRenderer.invoke('myreader:write-file', filePath, content), + listDirectory: (dirPath: string) => ipcRenderer.invoke('myreader:list-directory', dirPath), + parentDirectory: (dirPath: string) => ipcRenderer.invoke('myreader:parent-directory', dirPath), + resolveRelativePath: (baseFilePath: string, href: string) => + ipcRenderer.invoke('myreader:resolve-relative-path', baseFilePath, href), + openExternal: (url: string) => ipcRenderer.invoke('myreader:open-external', url), + defaultDirectory: () => ipcRenderer.invoke('myreader:default-directory'), + deleteFile: (filePath: string) => ipcRenderer.invoke('myreader:delete-file', filePath), + renamePath: (oldPath: string, newName: string) => + ipcRenderer.invoke('myreader:rename-path', oldPath, newName), + allowClose: () => { + ipcRenderer.send('myreader:allow-close') + }, + onRequestClose: (handler: () => void) => { + const listener = (): void => { + handler() + } + ipcRenderer.on('myreader:request-close', listener) + return () => { + ipcRenderer.removeListener('myreader:request-close', listener) + } + }, + onMenuAction: (handler: (action: string) => void) => { + const listener = (_e: unknown, action: string): void => { + handler(action) + } + ipcRenderer.on('myreader:menu', listener) + return () => { + ipcRenderer.removeListener('myreader:menu', listener) + } + } +} + +try { + contextBridge.exposeInMainWorld('myreader', api) +} catch (e) { + console.error('[MyReader] preload contextBridge failed', e) +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..aeb802a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,7231 @@ +{ + "name": "myreader", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "myreader", + "version": "0.1.0", + "dependencies": { + "@codemirror/commands": "^6.8.0", + "@codemirror/lang-markdown": "^6.3.2", + "@codemirror/language": "^6.11.0", + "@codemirror/state": "^6.5.2", + "@codemirror/view": "^6.36.4", + "dompurify": "^3.2.5", + "highlight.js": "^11.11.1", + "markdown-it": "^14.1.0", + "markdown-it-multimd-table": "^4.2.3", + "mermaid": "^11.15.0", + "react": "^19.1.0", + "react-dom": "^19.1.0" + }, + "devDependencies": { + "@types/markdown-it": "^14.1.2", + "@types/node": "^22.15.3", + "@types/react": "^19.1.2", + "@types/react-dom": "^19.1.2", + "@vitejs/plugin-react": "^4.4.1", + "electron": "^35.1.5", + "electron-builder": "^26.0.12", + "electron-vite": "^3.1.0", + "typescript": "^5.8.3", + "vite": "^6.3.4" + }, + "engines": { + "node": ">=20.10.0" + } + }, + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", + "license": "MIT", + "dependencies": { + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.3", + "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.29.3.tgz", + "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.3", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmmirror.com/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "license": "MIT" + }, + "node_modules/@chevrotain/types": { + "version": "11.1.2", + "resolved": "https://registry.npmmirror.com/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", + "license": "Apache-2.0" + }, + "node_modules/@codemirror/autocomplete": { + "version": "6.20.2", + "resolved": "https://registry.npmmirror.com/@codemirror/autocomplete/-/autocomplete-6.20.2.tgz", + "integrity": "sha512-G5FPkgIiLjOgZMjqVjvuKQ1rGPtHogLldJr33eFJdVLtmwY+giGrlv/ewljLz6b9BSQLkjxuwBc6g6omDM+YxQ==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.10.3", + "resolved": "https://registry.npmmirror.com/@codemirror/commands/-/commands-6.10.3.tgz", + "integrity": "sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.6.0", + "@codemirror/view": "^6.27.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/lang-css": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/@codemirror/lang-css/-/lang-css-6.3.1.tgz", + "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/css": "^1.1.7" + } + }, + "node_modules/@codemirror/lang-html": { + "version": "6.4.11", + "resolved": "https://registry.npmmirror.com/@codemirror/lang-html/-/lang-html-6.4.11.tgz", + "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/css": "^1.1.0", + "@lezer/html": "^1.3.12" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "6.2.5", + "resolved": "https://registry.npmmirror.com/@codemirror/lang-javascript/-/lang-javascript-6.2.5.tgz", + "integrity": "sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-markdown": { + "version": "6.5.0", + "resolved": "https://registry.npmmirror.com/@codemirror/lang-markdown/-/lang-markdown-6.5.0.tgz", + "integrity": "sha512-0K40bZ35jpHya6FriukbgaleaqzBLZfOh7HuzqbMxBXkbYMJDxfF39c23xOgxFezR+3G+tR2/Mup+Xk865OMvw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.7.1", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.3.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/markdown": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.12.3", + "resolved": "https://registry.npmmirror.com/@codemirror/language/-/language-6.12.3.tgz", + "integrity": "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.5.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.9.6", + "resolved": "https://registry.npmmirror.com/@codemirror/lint/-/lint-6.9.6.tgz", + "integrity": "sha512-6Kp7r6XfCi/D/5sdXieMfg9pJU1bUEx96WITuLU6ESaKizCz0QHFMjY/TaFSbigDdEAIgi93itLBIUETP4oK+A==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.42.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.6.0", + "resolved": "https://registry.npmmirror.com/@codemirror/state/-/state-6.6.0.tgz", + "integrity": "sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==", + "license": "MIT", + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.43.0", + "resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.43.0.tgz", + "integrity": "sha512-V7ZCLQO3Jus9hzh2jVCCPW3mO4IBMr43O37PqSUYautJSnnJF41YlgLw21x0fLJTYvJ+Vkm6Gp+qKGH9pltgXA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.6.0", + "crelt": "^1.0.6", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@develar/schema-utils": { + "version": "2.6.5", + "resolved": "https://registry.npmmirror.com/@develar/schema-utils/-/schema-utils-2.6.5.tgz", + "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@electron/asar": { + "version": "3.4.1", + "resolved": "https://registry.npmmirror.com/@electron/asar/-/asar-3.4.1.tgz", + "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "bin": { + "asar": "bin/asar.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@electron/asar/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@electron/asar/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/asar/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/fuses": { + "version": "1.8.0", + "resolved": "https://registry.npmmirror.com/@electron/fuses/-/fuses-1.8.0.tgz", + "integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.1", + "fs-extra": "^9.0.1", + "minimist": "^1.2.5" + }, + "bin": { + "electron-fuses": "dist/bin.js" + } + }, + "node_modules/@electron/fuses/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/fuses/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/fuses/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/get": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/@electron/get/-/get-2.0.3.tgz", + "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/@electron/notarize": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@electron/notarize/-/notarize-2.5.0.tgz", + "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/notarize/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/notarize/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/osx-sign": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/@electron/osx-sign/-/osx-sign-1.3.3.tgz", + "integrity": "sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "compare-version": "^0.1.2", + "debug": "^4.3.4", + "fs-extra": "^10.0.0", + "isbinaryfile": "^4.0.8", + "minimist": "^1.2.6", + "plist": "^3.0.5" + }, + "bin": { + "electron-osx-flat": "bin/electron-osx-flat.js", + "electron-osx-sign": "bin/electron-osx-sign.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@electron/osx-sign/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmmirror.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/@electron/osx-sign/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/osx-sign/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/rebuild": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/@electron/rebuild/-/rebuild-4.0.4.tgz", + "integrity": "sha512-Rzc39XPdk/+/wBG8MfwAHohXflep0ITUfulb6Rgz3R0NeSB1noE+E9/M/cb8ftCAiyDD9PPhLuuWgE1GaInbKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@malept/cross-spawn-promise": "^2.0.0", + "debug": "^4.1.1", + "node-abi": "^4.2.0", + "node-api-version": "^0.2.1", + "node-gyp": "^12.2.0", + "read-binary-file-arch": "^1.0.6" + }, + "bin": { + "electron-rebuild": "lib/cli.js" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@electron/universal": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/@electron/universal/-/universal-2.0.3.tgz", + "integrity": "sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "^3.3.1", + "@malept/cross-spawn-promise": "^2.0.0", + "debug": "^4.3.1", + "dir-compare": "^4.2.0", + "fs-extra": "^11.1.1", + "minimatch": "^9.0.3", + "plist": "^3.1.0" + }, + "engines": { + "node": ">=16.4" + } + }, + "node_modules/@electron/universal/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@electron/universal/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@electron/universal/node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/universal/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/universal/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@electron/universal/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/windows-sign": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/@electron/windows-sign/-/windows-sign-1.2.2.tgz", + "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "dependencies": { + "cross-dirname": "^0.1.0", + "debug": "^4.3.4", + "fs-extra": "^11.1.1", + "minimist": "^1.2.8", + "postject": "^1.0.0-alpha.6" + }, + "bin": { + "electron-windows-sign": "bin/electron-windows-sign.js" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/windows-sign/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/@iconify/utils/-/utils-3.1.3.tgz", + "integrity": "sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "import-meta-resolve": "^4.2.0" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lezer/common": { + "version": "1.5.2", + "resolved": "https://registry.npmmirror.com/@lezer/common/-/common-1.5.2.tgz", + "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==", + "license": "MIT" + }, + "node_modules/@lezer/css": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/@lezer/css/-/css-1.3.3.tgz", + "integrity": "sha512-RzBo8r+/6QJeow7aPHIpGVIH59xTcJXp399820gZoMo9noQDRVpJLheIBUicYwKcsbOYoBRoLZlf2720dG/4Tg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/@lezer/highlight/-/highlight-1.2.3.tgz", + "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.3.0" + } + }, + "node_modules/@lezer/html": { + "version": "1.3.13", + "resolved": "https://registry.npmmirror.com/@lezer/html/-/html-1.3.13.tgz", + "integrity": "sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/@lezer/javascript/-/javascript-1.5.4.tgz", + "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.10", + "resolved": "https://registry.npmmirror.com/@lezer/lr/-/lr-1.4.10.tgz", + "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/markdown": { + "version": "1.6.3", + "resolved": "https://registry.npmmirror.com/@lezer/markdown/-/markdown-1.6.3.tgz", + "integrity": "sha512-jpGm5Ps+XErS+xA4urw7ogEGkeZOahVQF21Z6oECF0sj+2liwZopd2+I8uH5I/vZsRuuze3OxBREIANLf6KKUw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.5.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@malept/cross-spawn-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", + "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/@malept/flatpak-bundler": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", + "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.0", + "lodash": "^4.17.15", + "tmp-promise": "^3.0.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", + "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", + "license": "MIT" + }, + "node_modules/@mermaid-js/parser": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@mermaid-js/parser/-/parser-1.1.1.tgz", + "integrity": "sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==", + "license": "MIT", + "dependencies": { + "@chevrotain/types": "~11.1.1" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz", + "integrity": "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz", + "integrity": "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz", + "integrity": "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz", + "integrity": "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz", + "integrity": "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz", + "integrity": "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz", + "integrity": "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz", + "integrity": "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz", + "integrity": "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz", + "integrity": "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz", + "integrity": "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz", + "integrity": "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz", + "integrity": "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz", + "integrity": "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz", + "integrity": "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz", + "integrity": "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz", + "integrity": "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz", + "integrity": "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz", + "integrity": "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz", + "integrity": "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz", + "integrity": "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz", + "integrity": "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz", + "integrity": "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz", + "integrity": "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz", + "integrity": "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmmirror.com/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmmirror.com/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmmirror.com/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmmirror.com/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmmirror.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmmirror.com/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmmirror.com/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmmirror.com/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmmirror.com/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmmirror.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmmirror.com/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmmirror.com/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmmirror.com/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmmirror.com/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmmirror.com/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmmirror.com/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmmirror.com/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmmirror.com/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmmirror.com/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.19", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/plist": { + "version": "3.0.5", + "resolved": "https://registry.npmmirror.com/@types/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*", + "xmlbuilder": ">=11.0.1" + } + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmmirror.com/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmmirror.com/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/verror": { + "version": "1.10.11", + "resolved": "https://registry.npmmirror.com/@types/verror/-/verror-1.10.11.tgz", + "integrity": "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmmirror.com/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmmirror.com/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.13", + "resolved": "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.13.tgz", + "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/7zip-bin": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/7zip-bin/-/7zip-bin-5.2.0.tgz", + "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/abbrev": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/abbrev/-/abbrev-4.0.0.tgz", + "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/app-builder-bin": { + "version": "5.0.0-alpha.12", + "resolved": "https://registry.npmmirror.com/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz", + "integrity": "sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/app-builder-lib": { + "version": "26.8.1", + "resolved": "https://registry.npmmirror.com/app-builder-lib/-/app-builder-lib-26.8.1.tgz", + "integrity": "sha512-p0Im/Dx5C4tmz8QEE1Yn4MkuPC8PrnlRneMhWJj7BBXQfNTJUshM/bp3lusdEsDbvvfJZpXWnYesgSLvwtM2Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@develar/schema-utils": "~2.6.5", + "@electron/asar": "3.4.1", + "@electron/fuses": "^1.8.0", + "@electron/get": "^3.0.0", + "@electron/notarize": "2.5.0", + "@electron/osx-sign": "1.3.3", + "@electron/rebuild": "^4.0.3", + "@electron/universal": "2.0.3", + "@malept/flatpak-bundler": "^0.4.0", + "@types/fs-extra": "9.0.13", + "async-exit-hook": "^2.0.1", + "builder-util": "26.8.1", + "builder-util-runtime": "9.5.1", + "chromium-pickle-js": "^0.2.0", + "ci-info": "4.3.1", + "debug": "^4.3.4", + "dotenv": "^16.4.5", + "dotenv-expand": "^11.0.6", + "ejs": "^3.1.8", + "electron-publish": "26.8.1", + "fs-extra": "^10.1.0", + "hosted-git-info": "^4.1.0", + "isbinaryfile": "^5.0.0", + "jiti": "^2.4.2", + "js-yaml": "^4.1.0", + "json5": "^2.2.3", + "lazy-val": "^1.0.5", + "minimatch": "^10.0.3", + "plist": "3.1.0", + "proper-lockfile": "^4.1.2", + "resedit": "^1.7.0", + "semver": "~7.7.3", + "tar": "^7.5.7", + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0", + "which": "^5.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "dmg-builder": "26.8.1", + "electron-builder-squirrel-windows": "26.8.1" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/@electron/get/-/get-3.1.0.tgz", + "integrity": "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/app-builder-lib/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmmirror.com/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmmirror.com/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.29", + "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.29.tgz", + "integrity": "sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmmirror.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builder-util": { + "version": "26.8.1", + "resolved": "https://registry.npmmirror.com/builder-util/-/builder-util-26.8.1.tgz", + "integrity": "sha512-pm1lTYbGyc90DHgCDO7eo8Rl4EqKLciayNbZqGziqnH9jrlKe8ZANGdityLZU+pJh16dfzjAx2xQq9McuIPEtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.6", + "7zip-bin": "~5.2.0", + "app-builder-bin": "5.0.0-alpha.12", + "builder-util-runtime": "9.5.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.6", + "debug": "^4.3.4", + "fs-extra": "^10.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "js-yaml": "^4.1.0", + "sanitize-filename": "^1.6.3", + "source-map-support": "^0.5.19", + "stat-mode": "^1.0.0", + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0" + } + }, + "node_modules/builder-util-runtime": { + "version": "9.5.1", + "resolved": "https://registry.npmmirror.com/builder-util-runtime/-/builder-util-runtime-9.5.1.tgz", + "integrity": "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/builder-util/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/builder-util/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/builder-util/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmmirror.com/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmmirror.com/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001792", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz", + "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/compare-version": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmmirror.com/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "license": "MIT" + }, + "node_modules/cross-dirname": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/cross-dirname/-/cross-dirname-0.1.0.tgz", + "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cytoscape": { + "version": "3.33.3", + "resolved": "https://registry.npmmirror.com/cytoscape/-/cytoscape-3.33.3.tgz", + "integrity": "sha512-Gej7U+OKR+LZ8kvX7rb2HhCYJ0IhvEFsnkud4SB1PR+BUY/TsSO0dmOW59WEVLu51b1Rm+gQRKoz4bLYxGSZ2g==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "license": "MIT" + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmmirror.com/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmmirror.com/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmmirror.com/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmmirror.com/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.14", + "resolved": "https://registry.npmmirror.com/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, + "node_modules/dayjs": { + "version": "1.11.20", + "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.20.tgz", + "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/dir-compare": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/dir-compare/-/dir-compare-4.2.0.tgz", + "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.5", + "p-limit": "^3.1.0 " + } + }, + "node_modules/dir-compare/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/dir-compare/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/dir-compare/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dmg-builder": { + "version": "26.8.1", + "resolved": "https://registry.npmmirror.com/dmg-builder/-/dmg-builder-26.8.1.tgz", + "integrity": "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "26.8.1", + "builder-util": "26.8.1", + "fs-extra": "^10.1.0", + "iconv-lite": "^0.6.2", + "js-yaml": "^4.1.0" + }, + "optionalDependencies": { + "dmg-license": "^1.0.11" + } + }, + "node_modules/dmg-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dmg-builder/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/dmg-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/dmg-license": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/dmg-license/-/dmg-license-1.0.11.tgz", + "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "@types/plist": "^3.0.1", + "@types/verror": "^1.10.3", + "ajv": "^6.10.0", + "crc": "^3.8.0", + "iconv-corefoundation": "^1.1.7", + "plist": "^3.0.4", + "smart-buffer": "^4.0.2", + "verror": "^1.10.0" + }, + "bin": { + "dmg-license": "bin/dmg-license.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dompurify": { + "version": "3.4.3", + "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.4.3.tgz", + "integrity": "sha512-VVwJidIJcp1hpg2OMXML3ZVRPYSZiq4aX7qBh83BSIpOaRDqI+qxhXjjIWnpzkOXhmp0L81lnoME1mnCc9H48A==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmmirror.com/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmmirror.com/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron": { + "version": "35.7.5", + "resolved": "https://registry.npmmirror.com/electron/-/electron-35.7.5.tgz", + "integrity": "sha512-dnL+JvLraKZl7iusXTVTGYs10TKfzUi30uEDTqsmTm0guN9V2tbOjTzyIZbh9n3ygUjgEYyo+igAwMRXIi3IPw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@electron/get": "^2.0.0", + "@types/node": "^22.7.7", + "extract-zip": "^2.0.1" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 12.20.55" + } + }, + "node_modules/electron-builder": { + "version": "26.8.1", + "resolved": "https://registry.npmmirror.com/electron-builder/-/electron-builder-26.8.1.tgz", + "integrity": "sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "26.8.1", + "builder-util": "26.8.1", + "builder-util-runtime": "9.5.1", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "dmg-builder": "26.8.1", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "simple-update-notifier": "2.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "electron-builder": "cli.js", + "install-app-deps": "install-app-deps.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/electron-builder-squirrel-windows": { + "version": "26.8.1", + "resolved": "https://registry.npmmirror.com/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.8.1.tgz", + "integrity": "sha512-o288fIdgPLHA76eDrFADHPoo7VyGkDCYbLV1GzndaMSAVBoZrGvM9m2IehdcVMzdAZJ2eV9bgyissQXHv5tGzA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "26.8.1", + "builder-util": "26.8.1", + "electron-winstaller": "5.4.0" + } + }, + "node_modules/electron-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-builder/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-publish": { + "version": "26.8.1", + "resolved": "https://registry.npmmirror.com/electron-publish/-/electron-publish-26.8.1.tgz", + "integrity": "sha512-q+jrSTIh/Cv4eGZa7oVR+grEJo/FoLMYBAnSL5GCtqwUpr1T+VgKB/dn1pnzxIxqD8S/jP1yilT9VrwCqINR4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/fs-extra": "^9.0.11", + "builder-util": "26.8.1", + "builder-util-runtime": "9.5.1", + "chalk": "^4.1.2", + "form-data": "^4.0.5", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "mime": "^2.5.2" + } + }, + "node_modules/electron-publish/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-publish/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-publish/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.356", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.356.tgz", + "integrity": "sha512-9NgFd7m5t5MCJ5rUSjJITUXAH9mEGlrlofnMf4YEr+pz6JlP7cWmTAH+JFmbPnaSW8koVTkuW7pacORWAnA5Yw==", + "dev": true, + "license": "ISC" + }, + "node_modules/electron-vite": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/electron-vite/-/electron-vite-3.1.0.tgz", + "integrity": "sha512-M7aAzaRvSl5VO+6KN4neJCYLHLpF/iWo5ztchI/+wMxIieDZQqpbCYfaEHHHPH6eupEzfvZdLYdPdmvGqoVe0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.26.10", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "cac": "^6.7.14", + "esbuild": "^0.25.1", + "magic-string": "^0.30.17", + "picocolors": "^1.1.1" + }, + "bin": { + "electron-vite": "bin/electron-vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@swc/core": "^1.0.0", + "vite": "^4.0.0 || ^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + } + } + }, + "node_modules/electron-winstaller": { + "version": "5.4.0", + "resolved": "https://registry.npmmirror.com/electron-winstaller/-/electron-winstaller-5.4.0.tgz", + "integrity": "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@electron/asar": "^3.2.1", + "debug": "^4.1.1", + "fs-extra": "^7.0.1", + "lodash": "^4.17.21", + "temp": "^0.9.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "@electron/windows-sign": "^1.1.2" + } + }, + "node_modules/electron-winstaller/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-toolkit": { + "version": "1.46.1", + "resolved": "https://registry.npmmirror.com/es-toolkit/-/es-toolkit-1.46.1.tgz", + "integrity": "sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "optional": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-agent/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmmirror.com/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmmirror.com/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-corefoundation": { + "version": "1.1.7", + "resolved": "https://registry.npmmirror.com/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", + "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "cli-truncate": "^2.1.0", + "node-addon-api": "^1.6.3" + }, + "engines": { + "node": "^8.11.2 || >=10" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isbinaryfile": { + "version": "5.0.7", + "resolved": "https://registry.npmmirror.com/isbinaryfile/-/isbinaryfile-5.0.7.tgz", + "integrity": "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmmirror.com/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/katex": { + "version": "0.16.46", + "resolved": "https://registry.npmmirror.com/katex/-/katex-0.16.46.tgz", + "integrity": "sha512-WHy4Coo+bGZyH7NwJKHkS04YFsFcarWbAEOAC3EMndzdN6VSZqklLLIgfxzyaW9jDoeGYJX9SWbJPKpecox0Uw==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" + }, + "node_modules/lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT" + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it-multimd-table": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/markdown-it-multimd-table/-/markdown-it-multimd-table-4.2.3.tgz", + "integrity": "sha512-KepCr2OMJqm7IT6sOIbuqHGe+NERhgy66XMrc5lo6dHW7oaPzMDtYwR1EGwK16/blb6mCSg4jqityOe0o/H7HA==", + "license": "MIT" + }, + "node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmmirror.com/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, + "node_modules/mermaid": { + "version": "11.15.0", + "resolved": "https://registry.npmmirror.com/mermaid/-/mermaid-11.15.0.tgz", + "integrity": "sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==", + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.1.1", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.1.1", + "@types/d3": "^7.4.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.1", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.19", + "dompurify": "^3.3.1", + "es-toolkit": "^1.45.1", + "katex": "^0.16.25", + "khroma": "^2.1.0", + "marked": "^16.3.0", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmmirror.com/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-abi": { + "version": "4.31.0", + "resolved": "https://registry.npmmirror.com/node-abi/-/node-abi-4.31.0.tgz", + "integrity": "sha512-Erq5w/t3syw3s4sDsUaX4QttIdBPsGKTT1DTRsCkTonGggczhlDKm/wDX3o+HPJpQ41EjXCbcmXf0tgr5YZJXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.6.3" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "1.7.2", + "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-api-version": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/node-api-version/-/node-api-version-0.2.1.tgz", + "integrity": "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + } + }, + "node_modules/node-api-version/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp": { + "version": "12.3.0", + "resolved": "https://registry.npmmirror.com/node-gyp/-/node-gyp-12.3.0.tgz", + "integrity": "sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "tar": "^7.5.4", + "tinyglobby": "^0.2.12", + "undici": "^6.25.0", + "which": "^6.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.44", + "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.44.tgz", + "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nopt": { + "version": "9.0.0", + "resolved": "https://registry.npmmirror.com/nopt/-/nopt-9.0.0.tgz", + "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "license": "MIT" + }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT" + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pe-library": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/pe-library/-/pe-library-0.4.1.tgz", + "integrity": "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postject": { + "version": "1.0.0-alpha.6", + "resolved": "https://registry.npmmirror.com/postject/-/postject-1.0.0-alpha.6.tgz", + "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "commander": "^9.4.0" + }, + "bin": { + "postject": "dist/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/postject/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react": { + "version": "19.2.6", + "resolved": "https://registry.npmmirror.com/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.6", + "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-19.2.6.tgz", + "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.6" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-binary-file-arch": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", + "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "bin": { + "read-binary-file-arch": "cli.js" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resedit": { + "version": "1.7.2", + "resolved": "https://registry.npmmirror.com/resedit/-/resedit-1.7.2.tgz", + "integrity": "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pe-library": "^0.4.1" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmmirror.com/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmmirror.com/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense" + }, + "node_modules/rollup": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.60.4.tgz", + "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.4", + "@rollup/rollup-android-arm64": "4.60.4", + "@rollup/rollup-darwin-arm64": "4.60.4", + "@rollup/rollup-darwin-x64": "4.60.4", + "@rollup/rollup-freebsd-arm64": "4.60.4", + "@rollup/rollup-freebsd-x64": "4.60.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", + "@rollup/rollup-linux-arm-musleabihf": "4.60.4", + "@rollup/rollup-linux-arm64-gnu": "4.60.4", + "@rollup/rollup-linux-arm64-musl": "4.60.4", + "@rollup/rollup-linux-loong64-gnu": "4.60.4", + "@rollup/rollup-linux-loong64-musl": "4.60.4", + "@rollup/rollup-linux-ppc64-gnu": "4.60.4", + "@rollup/rollup-linux-ppc64-musl": "4.60.4", + "@rollup/rollup-linux-riscv64-gnu": "4.60.4", + "@rollup/rollup-linux-riscv64-musl": "4.60.4", + "@rollup/rollup-linux-s390x-gnu": "4.60.4", + "@rollup/rollup-linux-x64-gnu": "4.60.4", + "@rollup/rollup-linux-x64-musl": "4.60.4", + "@rollup/rollup-openbsd-x64": "4.60.4", + "@rollup/rollup-openharmony-arm64": "4.60.4", + "@rollup/rollup-win32-arm64-msvc": "4.60.4", + "@rollup/rollup-win32-ia32-msvc": "4.60.4", + "@rollup/rollup-win32-x64-gnu": "4.60.4", + "@rollup/rollup-win32-x64-msvc": "4.60.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmmirror.com/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sanitize-filename": { + "version": "1.6.4", + "resolved": "https://registry.npmmirror.com/sanitize-filename/-/sanitize-filename-1.6.4.tgz", + "integrity": "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==", + "dev": true, + "license": "WTFPL OR ISC", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/stat-mode": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/stat-mode/-/stat-mode-1.0.0.tgz", + "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/style-mod": { + "version": "4.1.3", + "resolved": "https://registry.npmmirror.com/style-mod/-/style-mod-4.1.3.tgz", + "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", + "license": "MIT" + }, + "node_modules/stylis": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", + "license": "MIT" + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "7.5.15", + "resolved": "https://registry.npmmirror.com/tar/-/tar-7.5.15.tgz", + "integrity": "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/temp": { + "version": "0.9.4", + "resolved": "https://registry.npmmirror.com/temp/-/temp-0.9.4.tgz", + "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mkdirp": "^0.5.1", + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp-file": { + "version": "3.4.0", + "resolved": "https://registry.npmmirror.com/temp-file/-/temp-file-3.4.0.tgz", + "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^10.0.0" + } + }, + "node_modules/temp-file/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/temp-file/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/temp-file/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/tiny-async-pool": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", + "integrity": "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^5.5.0" + } + }, + "node_modules/tiny-async-pool/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tinyexec": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/tinyexec/-/tinyexec-1.1.2.tgz", + "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmmirror.com/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, + "node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, + "node_modules/undici": { + "version": "6.25.0", + "resolved": "https://registry.npmmirror.com/undici/-/undici-6.25.0.tgz", + "integrity": "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", + "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/uuid": { + "version": "14.0.0", + "resolved": "https://registry.npmmirror.com/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/verror": { + "version": "1.10.1", + "resolved": "https://registry.npmmirror.com/verror/-/verror-1.10.1.tgz", + "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/vite": { + "version": "6.4.2", + "resolved": "https://registry.npmmirror.com/vite/-/vite-6.4.2.tgz", + "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmmirror.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, + "node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmmirror.com/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..08ad63e --- /dev/null +++ b/package.json @@ -0,0 +1,81 @@ +{ + "name": "myreader", + "productName": "Huangzhijun's Reader", + "version": "0.1.0", + "description": "Huangzhijun's Reader — local Markdown reader and editor (Electron + React)", + "main": "./out/main/index.js", + "type": "module", + "config": { + "electron_mirror": "https://npmmirror.com/mirrors/electron/" + }, + "engines": { + "node": ">=20.10.0" + }, + "scripts": { + "dev": "electron-vite dev", + "build": "electron-vite build", + "preview": "electron-vite preview", + "typecheck": "tsc --noEmit", + "dist": "npm run build && electron-builder --win" + }, + "dependencies": { + "@codemirror/commands": "^6.8.0", + "@codemirror/lang-markdown": "^6.3.2", + "@codemirror/language": "^6.11.0", + "@codemirror/state": "^6.5.2", + "@codemirror/view": "^6.36.4", + "dompurify": "^3.2.5", + "highlight.js": "^11.11.1", + "markdown-it": "^14.1.0", + "markdown-it-multimd-table": "^4.2.3", + "mermaid": "^11.15.0", + "react": "^19.1.0", + "react-dom": "^19.1.0" + }, + "devDependencies": { + "@types/markdown-it": "^14.1.2", + "@types/node": "^22.15.3", + "@types/react": "^19.1.2", + "@types/react-dom": "^19.1.2", + "@vitejs/plugin-react": "^4.4.1", + "electron": "^35.1.5", + "electron-builder": "^26.0.12", + "electron-vite": "^3.1.0", + "typescript": "^5.8.3", + "vite": "^6.3.4" + }, + "build": { + "appId": "com.myreader.app", + "productName": "Huangzhijun's Reader", + "asar": true, + "directories": { + "output": "release" + }, + "files": [ + "out/**/*", + "package.json", + "resources/**/*" + ], + "electronDownload": { + "mirror": "https://npmmirror.com/mirrors/electron/" + }, + "win": { + "icon": "resources/app-icon.png", + "target": [ + { + "target": "nsis", + "arch": [ + "x64" + ] + } + ], + "artifactName": "${productName}-${version}-${arch}.${ext}" + }, + "nsis": { + "oneClick": false, + "allowToChangeInstallationDirectory": true, + "shortcutName": "Huangzhijun's Reader", + "perMachine": false + } + } +} diff --git a/resources/app-icon.png b/resources/app-icon.png new file mode 100644 index 0000000..004eb60 Binary files /dev/null and b/resources/app-icon.png differ diff --git a/src/renderer/index.html b/src/renderer/index.html new file mode 100644 index 0000000..8aff4bc --- /dev/null +++ b/src/renderer/index.html @@ -0,0 +1,12 @@ + + + + + + Huangzhijun's Reader + + +
+ + + diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx new file mode 100644 index 0000000..e040d8a --- /dev/null +++ b/src/renderer/src/App.tsx @@ -0,0 +1,1545 @@ +import * as React from 'react' +import { EditorPane, type MarkdownEditorHandle } from './EditorPane' +import type { EditorView } from '@codemirror/view' +import { MarkdownFormatToolbar } from './MarkdownFormatToolbar' +import { OutlinePanel } from './OutlinePanel' +import { PreviewArticle } from './PreviewArticle' +import { + extractOutline, + previewLineCenterInShell, + renderMarkdown, + scrollPreviewToSourceLine, + type OutlineItem +} from './markdown' +import { + addFileHistory, + historyFileName, + loadFileHistory, + removeFileHistory +} from './fileHistory' +import { BACKGROUNDS, FONTS, validBackgroundId, validFontId, type ViewMode } from './appearance' +import { COLOR_SWATCH_ROWS } from './colorPresets' + +type Tab = { + id: string + filePath: string | null + content: string + savedContent: string +} + +const BG_KEY = 'myreader-bg-id' +const FONT_KEY = 'myreader-font-id' +const VIEW_KEY = 'myreader-view' +const LEGACY_READ_KEY = 'myreader-read' +const BROWSE_KEY = 'myreader-browse' +const SIDEBAR_W_KEY = 'myreader-sidebar-w' +const SIDEBAR_HIDDEN_KEY = 'myreader-sidebar-hidden' +const SPLIT_KEY = 'myreader-split' +const PREVIEW_W_KEY = 'myreader-preview-max' +const SESSION_KEY = 'myreader-session-v1' +const PREVIEW_LINE_KEY = 'myreader-preview-line-height' + +function loadPreviewLineHeight(): string { + const raw = localStorage.getItem(PREVIEW_LINE_KEY) + if (!raw) return '1.5' + const n = Number.parseFloat(raw) + if (!Number.isFinite(n)) return '1.5' + return String(Math.min(3, Math.max(1, n))) +} + +type SessionTabRow = { path: string | null; content: string; saved: string } +type SessionV1 = { v: 1; activeIndex: number; tabs: SessionTabRow[]; bgId?: string; fontId?: string } + +function clamp(n: number, min: number, max: number): number { + return Math.min(max, Math.max(min, n)) +} + +function normalizePathKey(p: string): string { + return p.replace(/\\/g, '/').toLowerCase() +} + +function newTab(): Tab { + const id = crypto.randomUUID() + return { id, filePath: null, content: '', savedContent: '' } +} + +function tabLabel(t: Tab): string { + if (t.filePath) { + const parts = t.filePath.split(/[/\\]/) + return parts[parts.length - 1] || t.filePath + } + return '未命名' +} + +function isDirty(t: Tab): boolean { + return t.content !== t.savedContent +} + +function loadViewMode(): ViewMode { + const v = localStorage.getItem(VIEW_KEY) as ViewMode | null + if (v === 'edit' || v === 'read' || v === 'hybrid') return v + if (localStorage.getItem(LEGACY_READ_KEY) === '1') return 'read' + if (localStorage.getItem(LEGACY_READ_KEY) === '0') return 'edit' + return 'read' +} + +function viewModeLabel(m: ViewMode): string { + if (m === 'edit') return '编辑' + if (m === 'read') return '阅读' + return '分栏' +} + +export default function App(): React.ReactElement { + const api = window.myreader + const editorRef = React.useRef(null) + const [tabs, setTabs] = React.useState([]) + const [activeId, setActiveId] = React.useState('') + const [sessionHydrated, setSessionHydrated] = React.useState(false) + const [viewMode, setViewMode] = React.useState(() => loadViewMode()) + const [bgId, setBgId] = React.useState(() => { + return ( + validBackgroundId(localStorage.getItem(BG_KEY)) ?? + validBackgroundId(localStorage.getItem('myreader-theme')) ?? + validBackgroundId(localStorage.getItem('myreader-bg')) ?? + '1' + ) + }) + const [fontId, setFontId] = React.useState(() => { + return validFontId(localStorage.getItem(FONT_KEY)) ?? '0' + }) + const [previewLineHeight, setPreviewLineHeight] = React.useState(() => loadPreviewLineHeight()) + const [browseDir, setBrowseDir] = React.useState('') + const [dirEntries, setDirEntries] = React.useState< + { name: string; path: string; kind: 'file' | 'dir' }[] + >([]) + const [dirError, setDirError] = React.useState(null) + const [sidebarTab, setSidebarTab] = React.useState<'files' | 'history' | 'outline'>('files') + const [gotoLine, setGotoLine] = React.useState<{ line: number; seq: number } | null>(null) + const [parentDisabled, setParentDisabled] = React.useState(false) + const [sidebarHidden, setSidebarHidden] = React.useState( + () => localStorage.getItem(SIDEBAR_HIDDEN_KEY) === '1' + ) + const [sidebarWidth, setSidebarWidth] = React.useState(() => { + const n = Number(localStorage.getItem(SIDEBAR_W_KEY) ?? '260') + return Number.isFinite(n) ? clamp(n, 160, 560) : 260 + }) + const [splitPct, setSplitPct] = React.useState(() => { + const n = Number(localStorage.getItem(SPLIT_KEY) ?? '48') + return Number.isFinite(n) ? clamp(n, 22, 78) : 48 + }) + const [previewMaxWidth, setPreviewMaxWidth] = React.useState(() => { + const n = Number(localStorage.getItem(PREVIEW_W_KEY) ?? '880') + return Number.isFinite(n) ? clamp(n, 420, 1400) : 880 + }) + const [closePromptTabId, setClosePromptTabId] = React.useState(null) + const [ctxMenu, setCtxMenu] = React.useState<{ + x: number + y: number + path: string + kind: 'file' | 'dir' + } | null>(null) + const [textPrompt, setTextPrompt] = React.useState<{ + title: string + defaultValue: string + resolve: (v: string | null) => void + } | null>(null) + const [textPromptInput, setTextPromptInput] = React.useState('') + const [imageInsert, setImageInsert] = React.useState<{ + resolve: (v: { url: string; alt: string } | null) => void + } | null>(null) + const [imageUrlInput, setImageUrlInput] = React.useState('') + const [imageAltInput, setImageAltInput] = React.useState('图片') + const [colorPicker, setColorPicker] = React.useState<{ + resolve: (v: string | null) => void + } | null>(null) + const [colorHexInput, setColorHexInput] = React.useState('#dc2626') + const [fileHistory, setFileHistory] = React.useState(() => loadFileHistory()) + const [histCtxMenu, setHistCtxMenu] = React.useState<{ + x: number + y: number + path: string + } | null>(null) + const readPreviewOuterRef = React.useRef(null) + const readPreviewArticleRef = React.useRef(null) + const hybridPreviewRef = React.useRef(null) + const hybridPreviewShellRef = React.useRef(null) + const hybridPreviewArticleRef = React.useRef(null) + const hybridEditorViewRef = React.useRef(null) + const [hybridViewEpoch, setHybridViewEpoch] = React.useState(0) + const [hybridLinePulse, setHybridLinePulse] = React.useState<{ + topPx: number + seq: number + } | null>(null) + + const activeTab = tabs.find((t) => t.id === activeId) ?? null + const activeDoc = activeTab?.content ?? '' + const activeLineCount = React.useMemo( + () => (activeDoc ? activeDoc.split(/\r?\n/).length : 1), + [activeDoc] + ) + + const tabsRef = React.useRef(tabs) + tabsRef.current = tabs + + const refreshDir = React.useCallback(async (): Promise => { + if (!api || !browseDir) { + setDirEntries([]) + return + } + const res = await api.listDirectory(browseDir) + setDirError(res.error ?? null) + setDirEntries(res.entries) + if (api) { + const parent = await api.parentDirectory(browseDir) + setParentDisabled(parent === browseDir) + } + }, [api, browseDir]) + + React.useEffect(() => { + void refreshDir() + }, [refreshDir]) + + React.useEffect(() => { + if (!api) return + void (async () => { + const stored = localStorage.getItem(BROWSE_KEY) + if (stored) { + setBrowseDir(stored) + return + } + const d = await api.defaultDirectory() + setBrowseDir(d) + })() + }, [api]) + + React.useEffect(() => { + if (!api) { + setSessionHydrated(true) + return + } + let cancelled = false + void (async () => { + try { + const raw = localStorage.getItem(SESSION_KEY) + if (!raw) return + const data = JSON.parse(raw) as Partial + if (data.v !== 1 || !Array.isArray(data.tabs)) return + const restored: Tab[] = [] + for (const row of data.tabs) { + if (!row || typeof row !== 'object') continue + const id = crypto.randomUUID() + const content = typeof row.content === 'string' ? row.content : '' + const saved = typeof row.saved === 'string' ? row.saved : content + if (row.path) { + try { + await api.readFile(row.path) + restored.push({ id, filePath: row.path, content, savedContent: saved }) + } catch { + /* missing or unreadable */ + } + } else { + restored.push({ id, filePath: null, content, savedContent: saved }) + } + } + if (cancelled) return + setTabs(restored) + if (restored.length) { + let idx = typeof data.activeIndex === 'number' ? data.activeIndex : 0 + if (!Number.isFinite(idx)) idx = 0 + idx = Math.max(0, Math.min(idx, restored.length - 1)) + setActiveId(restored[idx]!.id) + } + if (typeof data.bgId === 'string') { + const b = validBackgroundId(data.bgId) + if (b) setBgId(b) + } + if (typeof data.fontId === 'string') { + const f = validFontId(data.fontId) + if (f) setFontId(f) + } + } catch { + /* ignore corrupt session */ + } finally { + if (!cancelled) setSessionHydrated(true) + } + })() + return () => { + cancelled = true + } + }, [api]) + + React.useEffect(() => { + if (!sessionHydrated) return + const id = window.setTimeout(() => { + const activeIndex = + tabs.length === 0 ? 0 : Math.max(0, tabs.findIndex((t) => t.id === activeId)) + const idx = + tabs.length === 0 + ? 0 + : activeIndex < 0 + ? 0 + : Math.min(activeIndex, tabs.length - 1) + const payload: SessionV1 = { + v: 1, + activeIndex: idx, + tabs: tabs.map((t) => ({ + path: t.filePath, + content: t.content, + saved: t.savedContent + })), + bgId, + fontId + } + localStorage.setItem(SESSION_KEY, JSON.stringify(payload)) + }, 400) + return () => window.clearTimeout(id) + }, [tabs, activeId, sessionHydrated, bgId, fontId]) + + React.useEffect(() => { + localStorage.setItem(BG_KEY, bgId) + document.documentElement.dataset.bg = bgId + }, [bgId]) + + React.useEffect(() => { + localStorage.setItem(FONT_KEY, fontId) + document.documentElement.dataset.font = fontId + }, [fontId]) + + React.useEffect(() => { + localStorage.setItem(PREVIEW_LINE_KEY, previewLineHeight) + document.documentElement.style.setProperty('--preview-line-height', previewLineHeight) + }, [previewLineHeight]) + + React.useEffect(() => { + localStorage.setItem(VIEW_KEY, viewMode) + }, [viewMode]) + + React.useEffect(() => { + localStorage.setItem(SIDEBAR_HIDDEN_KEY, sidebarHidden ? '1' : '0') + }, [sidebarHidden]) + + React.useEffect(() => { + localStorage.setItem(SIDEBAR_W_KEY, String(sidebarWidth)) + }, [sidebarWidth]) + + React.useEffect(() => { + localStorage.setItem(SPLIT_KEY, String(splitPct)) + }, [splitPct]) + + React.useEffect(() => { + localStorage.setItem(PREVIEW_W_KEY, String(previewMaxWidth)) + }, [previewMaxWidth]) + + React.useEffect(() => { + if (browseDir) localStorage.setItem(BROWSE_KEY, browseDir) + }, [browseDir]) + + React.useEffect(() => { + const onDoc = (): void => { + setCtxMenu(null) + setHistCtxMenu(null) + } + window.addEventListener('mousedown', onDoc) + return () => window.removeEventListener('mousedown', onDoc) + }, []) + + React.useEffect(() => { + if (textPrompt) setTextPromptInput(textPrompt.defaultValue) + }, [textPrompt]) + + React.useEffect(() => { + if (imageInsert) { + setImageUrlInput('') + setImageAltInput('图片') + } + }, [imageInsert]) + + React.useEffect(() => { + if (colorPicker) setColorHexInput('#dc2626') + }, [colorPicker]) + + React.useEffect(() => { + if (viewMode !== 'hybrid') setHybridLinePulse(null) + }, [viewMode]) + + const requestText = React.useCallback((title: string, defaultValue: string) => { + return new Promise((resolve) => { + setTextPrompt({ title, defaultValue, resolve }) + }) + }, []) + + const requestImageDetails = React.useCallback((): Promise<{ url: string; alt: string } | null> => { + return new Promise((resolve) => { + setImageInsert({ resolve }) + }) + }, []) + + const requestColor = React.useCallback((): Promise => { + return new Promise((resolve) => { + setColorPicker({ resolve }) + }) + }, []) + + React.useEffect(() => { + if (viewMode !== 'hybrid') return + const view = hybridEditorViewRef.current + const prevEl = hybridPreviewRef.current + if (!view || !prevEl) return + + const edScroll = view.scrollDOM + const maxScroll = (el: HTMLElement): number => Math.max(1, el.scrollHeight - el.clientHeight) + let syncing = false + + const syncFromEditor = (): void => { + if (syncing) return + syncing = true + const re = edScroll.scrollTop / maxScroll(edScroll) + prevEl.scrollTop = re * maxScroll(prevEl) + requestAnimationFrame(() => { + syncing = false + }) + } + const syncFromPreview = (): void => { + if (syncing) return + syncing = true + const rp = prevEl.scrollTop / maxScroll(prevEl) + edScroll.scrollTop = rp * maxScroll(edScroll) + requestAnimationFrame(() => { + syncing = false + }) + } + + edScroll.addEventListener('scroll', syncFromEditor, { passive: true }) + prevEl.addEventListener('scroll', syncFromPreview, { passive: true }) + requestAnimationFrame(() => { + syncFromEditor() + }) + return () => { + edScroll.removeEventListener('scroll', syncFromEditor) + prevEl.removeEventListener('scroll', syncFromPreview) + } + }, [viewMode, hybridViewEpoch, activeId]) + + React.useEffect(() => { + if (viewMode !== 'hybrid') return + const view = hybridEditorViewRef.current + const prevEl = hybridPreviewRef.current + if (!view || !prevEl) return + requestAnimationFrame(() => { + const edScroll = view.scrollDOM + const maxE = Math.max(1, edScroll.scrollHeight - edScroll.clientHeight) + const maxP = Math.max(1, prevEl.scrollHeight - prevEl.clientHeight) + const r = edScroll.scrollTop / maxE + prevEl.scrollTop = r * maxP + }) + }, [viewMode, activeDoc]) + + const onHybridViewReady = React.useCallback((view: EditorView | null) => { + hybridEditorViewRef.current = view + setHybridViewEpoch((e) => e + 1) + }, []) + + const onHybridCursorLine = React.useCallback( + (line: number) => { + requestAnimationFrame(() => { + const article = hybridPreviewArticleRef.current + const shell = hybridPreviewShellRef.current + if (!article || !shell) return + const topPx = previewLineCenterInShell(article, shell, line, activeLineCount) + if (topPx === null) return + setHybridLinePulse({ topPx, seq: Date.now() }) + }) + }, + [activeLineCount] + ) + + const navigateToOutline = React.useCallback( + (item: OutlineItem) => { + const line = item.line + if (viewMode === 'read') { + requestAnimationFrame(() => { + const scrollEl = readPreviewOuterRef.current + const article = readPreviewArticleRef.current + if (scrollEl && article) { + scrollPreviewToSourceLine(scrollEl, article, line, 'smooth', activeLineCount) + } + }) + return + } + setGotoLine({ line, seq: Date.now() }) + if (viewMode === 'hybrid') { + requestAnimationFrame(() => { + const scrollEl = hybridPreviewRef.current + const article = hybridPreviewArticleRef.current + const shell = hybridPreviewShellRef.current + if (scrollEl && article) { + scrollPreviewToSourceLine(scrollEl, article, line, 'smooth', activeLineCount) + } + if (article && shell) { + const topPx = previewLineCenterInShell(article, shell, line, activeLineCount) + if (topPx !== null) setHybridLinePulse({ topPx, seq: Date.now() }) + } + }) + } + }, + [viewMode, activeLineCount] + ) + + const outline = React.useMemo(() => extractOutline(activeDoc), [activeDoc]) + + const previewHtml = React.useMemo( + () => renderMarkdown(activeDoc, { baseFilePath: activeTab?.filePath ?? null }), + [activeDoc, activeTab?.filePath] + ) + + const recordFileOpen = React.useCallback((path: string): void => { + if (!/\.(md|markdown)$/i.test(path)) return + setFileHistory((prev) => addFileHistory(prev, path)) + }, []) + + const pickLocalImage = React.useCallback(async (): Promise => { + if (!api) return + const overlay = document.querySelector('.modal-overlay') + if (overlay) overlay.style.visibility = 'hidden' + try { + const r = await api.openImageDialog() + if (!r.canceled && r.url) setImageUrlInput(r.url) + } finally { + if (overlay) overlay.style.visibility = '' + } + }, [api]) + + const updateActive = React.useCallback( + (fn: (t: Tab) => Tab): void => { + if (!activeId) return + setTabs((prev) => prev.map((t) => (t.id === activeId ? fn(t) : t))) + }, + [activeId] + ) + + const onEditorChange = React.useCallback( + (next: string) => { + updateActive((t) => ({ ...t, content: next })) + }, + [updateActive] + ) + + const editorMountKey = activeTab ? `${activeTab.id}-${viewMode}` : `empty-${viewMode}` + + const scrollPreviewToAnchorId = React.useCallback( + (anchorId: string, mode: ViewMode = viewMode): void => { + const id = decodeURIComponent(anchorId) + if (!id) return + requestAnimationFrame(() => { + requestAnimationFrame(() => { + const article = + mode === 'read' ? readPreviewArticleRef.current : hybridPreviewArticleRef.current + if (!article) return + let el: Element | null = null + try { + el = article.querySelector(`#${CSS.escape(id)}`) + } catch { + el = article.querySelector(`#${id}`) + } + if (!el) el = document.getElementById(id) + el?.scrollIntoView({ behavior: 'smooth', block: 'start' }) + }) + }) + }, + [viewMode] + ) + + const openPathInTab = React.useCallback( + async (path: string, anchorId?: string): Promise => { + if (!api) return + try { + const key = normalizePathKey(path) + const existing = tabsRef.current.find( + (t) => t.filePath && normalizePathKey(t.filePath) === key + ) + if (existing) { + setActiveId(existing.id) + setBrowseDir(await api.parentDirectory(path)) + recordFileOpen(path) + if (anchorId) scrollPreviewToAnchorId(anchorId) + return + } + const content = await api.readFile(path) + const parent = await api.parentDirectory(path) + setBrowseDir(parent) + const nt: Tab = { id: crypto.randomUUID(), filePath: path, content, savedContent: content } + setTabs((prev) => [...prev, nt]) + setActiveId(nt.id) + setViewMode('read') + recordFileOpen(path) + if (anchorId) scrollPreviewToAnchorId(anchorId, 'read') + } catch (e) { + const msg = e instanceof Error ? e.message : String(e) + window.alert(`无法打开文件:${msg}`) + } + }, + [api, recordFileOpen, scrollPreviewToAnchorId] + ) + + const openFileDialog = React.useCallback(async (): Promise => { + if (!api) return + const r = await api.openFileDialog() + if (r.canceled || !r.path || r.content === undefined) return + const existing = tabsRef.current.find( + (t) => r.path && t.filePath && normalizePathKey(t.filePath) === normalizePathKey(r.path) + ) + if (existing) { + setActiveId(existing.id) + setBrowseDir(await api.parentDirectory(r.path)) + recordFileOpen(r.path) + return + } + setViewMode('read') + const nt: Tab = { + id: crypto.randomUUID(), + filePath: r.path, + content: r.content, + savedContent: r.content + } + setTabs((prev) => [...prev, nt]) + setActiveId(nt.id) + recordFileOpen(r.path) + }, [api, recordFileOpen]) + + const saveTabById = React.useCallback( + async (tabId: string): Promise => { + if (!api) return false + const t = tabsRef.current.find((x) => x.id === tabId) + if (!t) return false + if (!t.filePath) { + const d = await api.saveFileDialog() + if (d.canceled || !d.path) return false + await api.writeFile(d.path, t.content) + setTabs((prev) => + prev.map((x) => (x.id === tabId ? { ...x, filePath: d.path!, savedContent: x.content } : x)) + ) + return true + } + await api.writeFile(t.filePath, t.content) + setTabs((prev) => + prev.map((x) => (x.id === tabId ? { ...x, savedContent: x.content } : x)) + ) + return true + }, + [api] + ) + + const saveActive = React.useCallback(async (): Promise => { + if (!activeId) return + await saveTabById(activeId) + }, [activeId, saveTabById]) + + const saveActiveAs = React.useCallback(async (): Promise => { + if (!api) return + const t = tabs.find((x) => x.id === activeId) + if (!t) return + const d = await api.saveFileDialog(t.filePath ?? undefined) + if (d.canceled || !d.path) return + await api.writeFile(d.path, t.content) + setTabs((prev) => + prev.map((x) => + x.id === activeId ? { ...x, filePath: d.path!, savedContent: x.content } : x + ) + ) + }, [api, activeId, tabs]) + + const removeTabById = React.useCallback((tabId: string): void => { + setTabs((prev) => { + if (prev.length <= 1) { + setActiveId('') + return [] + } + const idx = prev.findIndex((x) => x.id === tabId) + if (idx < 0) return prev + const next = prev.filter((x) => x.id !== tabId) + const pick = next[Math.min(idx, next.length - 1)]! + setActiveId(pick.id) + return next + }) + }, []) + + const requestCloseTab = React.useCallback( + (tabId: string): void => { + const t = tabsRef.current.find((x) => x.id === tabId) + if (!t) return + if (!isDirty(t)) { + removeTabById(tabId) + return + } + setClosePromptTabId(tabId) + }, + [removeTabById] + ) + + const newTabAction = React.useCallback((): void => { + setViewMode('edit') + const nt = newTab() + setTabs((prev) => [...prev, nt]) + setActiveId(nt.id) + }, []) + + const closeTabAction = React.useCallback((): void => { + requestCloseTab(activeId) + }, [activeId, requestCloseTab]) + + const tabNext = React.useCallback((): void => { + if (tabs.length === 0) return + const idx = tabs.findIndex((x) => x.id === activeId) + const n = tabs[(idx + 1) % tabs.length] + if (n) setActiveId(n.id) + }, [activeId, tabs]) + + const tabPrev = React.useCallback((): void => { + if (tabs.length === 0) return + const idx = tabs.findIndex((x) => x.id === activeId) + const n = tabs[(idx - 1 + tabs.length) % tabs.length] + if (n) setActiveId(n.id) + }, [activeId, tabs]) + + const cycleViewMode = React.useCallback((): void => { + setViewMode((m) => (m === 'edit' ? 'read' : m === 'read' ? 'hybrid' : 'edit')) + }, []) + + const openFolderDialog = React.useCallback(async (): Promise => { + if (!api) return + const r = await api.openFolderDialog() + if (r.canceled || !r.path) return + setBrowseDir(r.path) + }, [api]) + + const goParent = React.useCallback(async (): Promise => { + if (!api || !browseDir || parentDisabled) return + const p = await api.parentDirectory(browseDir) + if (p !== browseDir) setBrowseDir(p) + }, [api, browseDir, parentDisabled]) + + const startSidebarResize = React.useCallback((e: React.MouseEvent): void => { + e.preventDefault() + const startX = e.clientX + const startW = sidebarWidth + const onMove = (ev: MouseEvent): void => { + setSidebarWidth(clamp(startW + (ev.clientX - startX), 160, 560)) + } + const onUp = (): void => { + document.removeEventListener('mousemove', onMove) + document.removeEventListener('mouseup', onUp) + } + document.addEventListener('mousemove', onMove) + document.addEventListener('mouseup', onUp) + }, [sidebarWidth]) + + const startHybridSplitResize = React.useCallback((e: React.MouseEvent): void => { + e.preventDefault() + const shell = (e.currentTarget as HTMLElement).closest('.hybrid-row') + if (!shell) return + const onMove = (ev: MouseEvent): void => { + const rect = shell.getBoundingClientRect() + const x = ev.clientX - rect.left + const pct = clamp((x / Math.max(1, rect.width)) * 100, 22, 78) + setSplitPct(pct) + } + const onUp = (): void => { + document.removeEventListener('mousemove', onMove) + document.removeEventListener('mouseup', onUp) + } + document.addEventListener('mousemove', onMove) + document.addEventListener('mouseup', onUp) + }, []) + + const startPreviewWidthResize = React.useCallback( + (e: React.MouseEvent): void => { + e.preventDefault() + e.stopPropagation() + const startX = e.clientX + const startW = previewMaxWidth + const onMove = (ev: MouseEvent): void => { + setPreviewMaxWidth(clamp(startW + (ev.clientX - startX), 420, 1400)) + } + const onUp = (): void => { + document.removeEventListener('mousemove', onMove) + document.removeEventListener('mouseup', onUp) + } + document.addEventListener('mousemove', onMove) + document.addEventListener('mouseup', onUp) + }, + [previewMaxWidth] + ) + + const deleteFileAt = React.useCallback( + async (filePath: string): Promise => { + if (!api) return + const ok = window.confirm(`确定删除文件?\n${filePath}`) + if (!ok) return + const curActive = activeId + await api.deleteFile(filePath) + setTabs((prev) => { + const next = prev.filter((t) => t.filePath !== filePath) + if (next.length === 0) { + setActiveId('') + return [] + } + if (!next.some((t) => t.id === curActive)) { + setActiveId(next[0]!.id) + } + return next + }) + setCtxMenu(null) + void refreshDir() + }, + [api, activeId, refreshDir] + ) + + const renamePathEntry = React.useCallback( + async (oldPath: string): Promise => { + if (!api) return + const parts = oldPath.split(/[/\\]/) + const base = parts[parts.length - 1] ?? oldPath + const nn = await requestText('新名称(文件需带扩展名)', base) + if (nn === null || nn.trim() === '' || nn.trim() === base) return + const { newPath } = await api.renamePath(oldPath, nn.trim()) + setTabs((prev) => + prev.map((t) => (t.filePath === oldPath ? { ...t, filePath: newPath } : t)) + ) + setBrowseDir((cur) => { + if (!cur) return cur + if (cur === oldPath) return newPath + if (cur.startsWith(oldPath)) return newPath + cur.slice(oldPath.length) + return cur + }) + setCtxMenu(null) + void refreshDir() + }, + [api, refreshDir, requestText] + ) + + const handlersRef = React.useRef({ + openFileDialog: async (): Promise => {}, + saveActive: async (): Promise => {}, + saveActiveAs: async (): Promise => {}, + newTabAction: (): void => {}, + closeTabAction: (): void => {}, + tabNext: (): void => {}, + tabPrev: (): void => {} + }) + handlersRef.current = { + openFileDialog, + saveActive, + saveActiveAs, + newTabAction, + closeTabAction, + tabNext, + tabPrev + } + + React.useEffect(() => { + if (!api) return + const unsubClose = api.onRequestClose(() => { + try { + const anyDirty = tabsRef.current.some(isDirty) + if (!anyDirty) { + api.allowClose() + return + } + const ok = window.confirm('有未保存的标签,确定退出并丢弃更改?') + if (ok) api.allowClose() + } catch (e) { + console.error('[MyReader] request-close handler', e) + api.allowClose() + } + }) + const unsubMenu = api.onMenuAction((action) => { + void (async () => { + try { + const h = handlersRef.current + switch (action) { + case 'file-open': + await h.openFileDialog() + break + case 'file-save': + await h.saveActive() + break + case 'file-save-as': + await h.saveActiveAs() + break + case 'tab-new': + h.newTabAction() + break + case 'tab-close': + h.closeTabAction() + break + case 'tab-next': + h.tabNext() + break + case 'tab-prev': + h.tabPrev() + break + case 'toggle-read': + cycleViewMode() + break + case 'help-about': + window.alert( + " Huangzhijun's Reader 0.1 — 本地 Markdown 阅读与编辑 \n \n 作者:黄志军 \n 支持与协助(wx):liaofan199404" + ) + break + default: + break + } + } catch (e) { + console.error('[MyReader] menu action', action, e) + } + })() + }) + return () => { + unsubClose() + unsubMenu() + } + }, [api, cycleViewMode]) + + React.useEffect(() => { + if (!activeTab?.filePath || !api) return + void api.parentDirectory(activeTab.filePath).then(setBrowseDir) + }, [activeId, activeTab?.filePath, api]) + + if (!api) { + return ( +
+

请在 Electron 中运行以使用文件系统功能。

+
+ ) + } + + const renderPreviewArticle = (articleRef?: React.Ref): React.ReactElement => ( + api.resolveRelativePath(base, href)} + onOpenMarkdown={(path, anchorId) => openPathInTab(path, anchorId)} + onOpenExternal={(url) => api.openExternal(url)} + /> + ) + + const closePromptTab = closePromptTabId + ? tabsRef.current.find((t) => t.id === closePromptTabId) + : undefined + + return ( +
+ {closePromptTabId && closePromptTab ? ( +
setClosePromptTabId(null)} + > +
e.stopPropagation()} + > +

关闭标签

+

+ 「{tabLabel(closePromptTab)}」有未保存的更改,是否保存? +

+
+ + + +
+
+
+ ) : null} + + {textPrompt ? ( +
{ + if (e.target === e.currentTarget) { + textPrompt.resolve(null) + setTextPrompt(null) + } + }} + > +
e.stopPropagation()} + > +

{textPrompt.title}

+ setTextPromptInput(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault() + textPrompt.resolve(textPromptInput) + setTextPrompt(null) + } + if (e.key === 'Escape') { + e.preventDefault() + textPrompt.resolve(null) + setTextPrompt(null) + } + }} + autoFocus + /> +
+ + +
+
+
+ ) : null} + + {imageInsert ? ( +
{ + if (e.target === e.currentTarget) { + imageInsert.resolve(null) + setImageInsert(null) + } + }} + > +
e.stopPropagation()} + > +

插入图片

+

支持网络地址或本地图片文件(Markdown 中保存为 file:// 链接)。

+ +
+ +
+ +
+ + +
+
+
+ ) : null} + + {colorPicker ? ( +
{ + if (e.target === e.currentTarget) { + colorPicker.resolve(null) + setColorPicker(null) + } + }} + > +
e.stopPropagation()} + > +

文字颜色

+
+ 取色器 + setColorHexInput(e.target.value.toLowerCase())} + aria-label="色谱" + /> +
+ +
+ {COLOR_SWATCH_ROWS.map((row, ri) => ( +
+ {row.map((hex) => ( +
+ ))} +
+
+ + +
+
+
+ ) : null} + + {histCtxMenu ? ( +
e.stopPropagation()} + > + +
+ ) : null} + + {ctxMenu ? ( +
e.stopPropagation()} + > + + {ctxMenu.kind === 'file' ? ( + + ) : null} +
+ ) : null} + +
+ {tabs.map((t) => ( +
+ + +
+ ))} +
+ +
+ + + + + + +
+ + + +
+
+ +
+ {!sidebarHidden ? ( + <> + +
+ + ) : ( + + )} + +
+ {(viewMode === 'edit' || viewMode === 'hybrid') && activeTab ? ( + + ) : null} + {viewMode === 'read' ? ( + activeTab ? ( +
+
+ {renderPreviewArticle(readPreviewArticleRef)} +
+
+
+ ) : ( +
+ 请从侧栏选择文件、使用工具栏「打开」,或点击「新标签」开始编辑。 +
+ ) + ) : null} + + {viewMode === 'edit' ? ( + activeTab ? ( + + ) : ( +
+ 请从侧栏选择文件、使用工具栏「打开」,或点击「新标签」开始编辑。 +
+ ) + ) : null} + + {viewMode === 'hybrid' ? ( + activeTab ? ( +
+
+ +
+
+
+
+ {hybridLinePulse ? ( +
+ ) : null} + {renderPreviewArticle(hybridPreviewArticleRef)} +
+
+
+ ) : ( +
+ 请从侧栏选择文件、使用工具栏「打开」,或点击「新标签」开始编辑。 +
+ ) + ) : null} +
+
+
+ ) +} diff --git a/src/renderer/src/EditorPane.tsx b/src/renderer/src/EditorPane.tsx new file mode 100644 index 0000000..f369391 --- /dev/null +++ b/src/renderer/src/EditorPane.tsx @@ -0,0 +1,370 @@ +import * as React from 'react' +import { EditorSelection } from '@codemirror/state' +import { defaultKeymap, history, historyKeymap, indentWithTab } from '@codemirror/commands' +import { markdown } from '@codemirror/lang-markdown' +import { EditorState } from '@codemirror/state' +import { + EditorView, + highlightActiveLine, + keymap, + lineNumbers, + placeholder +} from '@codemirror/view' + +export type MarkdownEditorHandle = { + applyAction: (id: string) => void | Promise +} + +type Props = { + mountKey: string + value: string + onChange: (next: string) => void + gotoLine?: { line: number; seq: number } | null + showLineNumbers?: boolean + /** In Electron, `window.prompt` is unreliable; use an in-app prompt from the host. */ + requestText?: (title: string, defaultValue: string) => Promise + onViewReady?: (view: EditorView | null) => void + /** 分栏:根据光标所在行在编辑器可滚动内容中的垂直比例,对齐阅读区提示条。 */ + onHybridCursorLine?: (line: number) => void + requestImageDetails?: () => Promise<{ url: string; alt: string } | null> + requestColor?: () => Promise +} + +function getMainSelection(view: EditorView): { from: number; to: number } { + const r = view.state.selection.main + return { from: r.from, to: r.to } +} + +function wrap(view: EditorView, left: string, right: string): void { + const { from, to } = getMainSelection(view) + const sel = view.state.sliceDoc(from, to) + view.dispatch({ + changes: { from, to, insert: left + sel + right }, + selection: EditorSelection.range(from + left.length, from + left.length + sel.length) + }) + view.focus() +} + +function insertAtCursor(view: EditorView, text: string): void { + const { from, to } = getMainSelection(view) + view.dispatch({ + changes: { from, to, insert: text }, + selection: EditorSelection.cursor(from + text.length) + }) + view.focus() +} + +function insertLines(view: EditorView, text: string): void { + insertAtCursor(view, text) +} + +function linePrefixOnMainLine(view: EditorView, prefix: string): void { + const pos = view.state.selection.main.head + const line = view.state.doc.lineAt(pos) + const lineText = line.text + const hashes = /^#+\s/.exec(lineText)?.[0] ?? '' + let rest = lineText + if (hashes) rest = lineText.slice(hashes.length) + const newLine = prefix + rest + view.dispatch({ + changes: { from: line.from, to: line.to, insert: newLine }, + selection: EditorSelection.cursor(line.from + newLine.length) + }) + view.focus() +} + +function escapeMarkdownLinkFragment(s: string): string { + return s.replace(/\\/g, '\\\\').replace(/\[/g, '\\[').replace(/\]/g, '\\]') +} + +function sanitizeInlineColor(c: string): string { + const t = c.trim() + if (/^#[0-9a-fA-F]{3}$/.test(t)) { + const r = t[1]! + const g = t[2]! + const b = t[3]! + return `#${r}${r}${g}${g}${b}${b}` + } + if (/^#[0-9a-fA-F]{6}$/.test(t) || /^#[0-9a-fA-F]{8}$/.test(t)) return t.toLowerCase() + if (/^rgba?\(\s*[\d.\s%,]+\s*\)$/.test(t)) return t + if (/^hsla?\(\s*[\d.\s%,deg]+\s*\)$/.test(t)) return t + if (/^[\w-]{1,40}$/.test(t)) return t + return '#333333' +} + +function sanitizeLinkUrl(url: string): string { + const t = url.trim() || 'https://' + if (/^file:/i.test(t)) return `<${t.replace(/[<>]/g, '')}>` + return t.replace(/\)/g, '%29') +} + +type ActionDeps = { + requestText: (title: string, def: string) => Promise + requestImageDetails?: () => Promise<{ url: string; alt: string } | null> + requestColor?: () => Promise +} + +async function applyMarkdownAction(view: EditorView, id: string, deps: ActionDeps): Promise { + const { requestText, requestImageDetails, requestColor } = deps + try { + switch (id) { + case 'bold': + wrap(view, '**', '**') + break + case 'italic': + wrap(view, '*', '*') + break + case 'strike': + wrap(view, '~~', '~~') + break + case 'code': + wrap(view, '`', '`') + break + case 'codeBlock': + insertLines(view, '\n```\n\n```\n') + break + case 'link': { + const url = await requestText('链接地址', 'https://') + if (url === null) return + const { from, to } = getMainSelection(view) + const rawLabel = view.state.sliceDoc(from, to) || '链接文字' + const label = escapeMarkdownLinkFragment(rawLabel) + const insert = `[${label}](${sanitizeLinkUrl(url)})` + view.dispatch({ + changes: { from, to, insert }, + selection: EditorSelection.cursor(from + insert.length) + }) + view.focus() + break + } + case 'image': { + if (requestImageDetails) { + const det = await requestImageDetails() + if (!det?.url?.trim()) return + const alt = (det.alt ?? '图片').trim() || '图片' + insertAtCursor( + view, + `![${escapeMarkdownLinkFragment(alt)}](${sanitizeLinkUrl(det.url.trim())})` + ) + break + } + const url = await requestText('图片地址', 'https://') + if (url === null) return + const rawAlt = await requestText('替代文字', '图片') + if (rawAlt === null) return + const alt = escapeMarkdownLinkFragment(rawAlt || '图片') + insertAtCursor(view, `![${alt}](${sanitizeLinkUrl(url)})`) + break + } + case 'h1': + linePrefixOnMainLine(view, '# ') + break + case 'h2': + linePrefixOnMainLine(view, '## ') + break + case 'h3': + linePrefixOnMainLine(view, '### ') + break + case 'h4': + linePrefixOnMainLine(view, '#### ') + break + case 'h5': + linePrefixOnMainLine(view, '##### ') + break + case 'h6': + linePrefixOnMainLine(view, '###### ') + break + case 'ul': + linePrefixOnMainLine(view, '- ') + break + case 'ol': + linePrefixOnMainLine(view, '1. ') + break + case 'task': + linePrefixOnMainLine(view, '- [ ] ') + break + case 'quote': + linePrefixOnMainLine(view, '> ') + break + case 'hr': + insertLines(view, '\n---\n') + break + case 'table': + insertLines( + view, + '\n| 列1 | 列2 | 列3 |\n| --- | --- | --- |\n| | | |\n' + ) + break + case 'mark': + wrap(view, '', '') + break + case 'color': { + if (requestColor) { + const c = await requestColor() + if (c === null || !c.trim()) return + const color = sanitizeInlineColor(c) + wrap(view, ``, '') + break + } + const c = await requestText('颜色(如 #e11 或 red)', '#dc2626') + if (c === null || !c.trim()) return + const color = sanitizeInlineColor(c) + wrap(view, ``, '') + break + } + case 'sup': + wrap(view, '', '') + break + case 'sub': + wrap(view, '', '') + break + case 'kbd': + wrap(view, '', '') + break + case 'details': + insertLines(view, '\n
\n标题\n内容\n
\n') + break + case 'footnote': + insertLines(view, '[^1]\n\n[^1]: 脚注内容\n') + break + default: + break + } + } catch (e) { + console.error('[MyReader] toolbar action failed', id, e) + } +} + +export const EditorPane = React.forwardRef( + function EditorPane( + { + mountKey, + value, + onChange, + gotoLine, + showLineNumbers = true, + requestText, + onViewReady, + onHybridCursorLine, + requestImageDetails, + requestColor + }: Props, + ref + ): React.ReactElement { + const hostRef = React.useRef(null) + const viewRef = React.useRef(null) + const onChangeRef = React.useRef(onChange) + onChangeRef.current = onChange + + const requestTextRef = React.useRef(requestText) + requestTextRef.current = requestText + + const onViewReadyRef = React.useRef(onViewReady) + onViewReadyRef.current = onViewReady + + const onHybridCursorLineRef = React.useRef(onHybridCursorLine) + onHybridCursorLineRef.current = onHybridCursorLine + + const requestImageDetailsRef = React.useRef(requestImageDetails) + requestImageDetailsRef.current = requestImageDetails + + const requestColorRef = React.useRef(requestColor) + requestColorRef.current = requestColor + + React.useImperativeHandle( + ref, + () => ({ + applyAction: async (id: string) => { + const view = viewRef.current + if (!view) return + const rt = + requestTextRef.current ?? + ((title: string, def: string) => + Promise.resolve(window.prompt(title, def))) + await applyMarkdownAction(view, id, { + requestText: rt, + requestImageDetails: requestImageDetailsRef.current, + requestColor: requestColorRef.current + }) + } + }), + [] + ) + + React.useEffect(() => { + const host = hostRef.current + if (!host) return + host.replaceChildren() + + const view = new EditorView({ + parent: host, + state: EditorState.create({ + doc: value, + extensions: [ + history(), + markdown(), + ...(showLineNumbers ? [lineNumbers()] : []), + highlightActiveLine(), + keymap.of([...defaultKeymap, ...historyKeymap, indentWithTab]), + placeholder('在此编辑 Markdown…'), + EditorView.lineWrapping, + EditorView.updateListener.of((u) => { + if (u.docChanged) { + onChangeRef.current(u.state.doc.toString()) + } + }), + EditorView.updateListener.of((u) => { + if (!onHybridCursorLineRef.current) return + if (!u.selectionSet && !u.focusChanged && !u.docChanged) return + const pos = u.state.selection.main.head + const line = u.state.doc.lineAt(pos) + onHybridCursorLineRef.current(line.number - 1) + }), + EditorView.theme({ + '&': { + height: '100%', + fontSize: '14px', + fontFamily: 'var(--font-ui, system-ui, sans-serif)' + }, + '.cm-scroller': { fontFamily: 'inherit' }, + '.cm-content': { paddingBlock: '12px' } + }) + ] + }) + }) + viewRef.current = view + onViewReadyRef.current?.(view) + return () => { + onViewReadyRef.current?.(null) + view.destroy() + viewRef.current = null + host.replaceChildren() + } + }, [mountKey, showLineNumbers]) + + React.useEffect(() => { + const view = viewRef.current + if (!view) return + const cur = view.state.doc.toString() + if (cur !== value) { + view.dispatch({ + changes: { from: 0, to: cur.length, insert: value }, + selection: { anchor: 0 }, + scrollIntoView: true + }) + } + }, [value, mountKey]) + + React.useEffect(() => { + if (!gotoLine) return + const view = viewRef.current + if (!view) return + const lineNo = gotoLine.line + 1 + if (lineNo < 1 || lineNo > view.state.doc.lines) return + const line = view.state.doc.line(lineNo) + view.dispatch({ selection: { anchor: line.from }, scrollIntoView: true }) + }, [gotoLine]) + + return
+ } +) diff --git a/src/renderer/src/MarkdownFormatToolbar.tsx b/src/renderer/src/MarkdownFormatToolbar.tsx new file mode 100644 index 0000000..7378e66 --- /dev/null +++ b/src/renderer/src/MarkdownFormatToolbar.tsx @@ -0,0 +1,54 @@ +import * as React from 'react' +import type { MarkdownEditorHandle } from './EditorPane' + +const BUTTONS: { id: string; label: string }[] = [ + { id: 'h1', label: 'H1' }, + { id: 'h2', label: 'H2' }, + { id: 'h3', label: 'H3' }, + { id: 'h4', label: 'H4' }, + { id: 'h5', label: 'H5' }, + { id: 'h6', label: 'H6' }, + { id: 'bold', label: '加粗' }, + { id: 'italic', label: '斜体' }, + { id: 'strike', label: '删除线' }, + { id: 'code', label: '行内代码' }, + { id: 'codeBlock', label: '代码块' }, + { id: 'link', label: '链接' }, + { id: 'image', label: '图片' }, + { id: 'ul', label: '无序列表' }, + { id: 'ol', label: '有序列表' }, + { id: 'task', label: '任务' }, + { id: 'quote', label: '引用' }, + { id: 'hr', label: '分隔线' }, + { id: 'table', label: '表格' }, + { id: 'mark', label: '高亮' }, + { id: 'color', label: '颜色' }, + { id: 'sup', label: '上标' }, + { id: 'sub', label: '下标' }, + { id: 'kbd', label: '按键' }, + { id: 'details', label: '折叠' }, + { id: 'footnote', label: '脚注' } +] + +type Props = { + editorRef: React.RefObject +} + +export function MarkdownFormatToolbar({ editorRef }: Props): React.ReactElement { + return ( +
+
+ {BUTTONS.map((b) => ( + + ))} +
+
+ ) +} diff --git a/src/renderer/src/OutlinePanel.tsx b/src/renderer/src/OutlinePanel.tsx new file mode 100644 index 0000000..cc98e50 --- /dev/null +++ b/src/renderer/src/OutlinePanel.tsx @@ -0,0 +1,110 @@ +import * as React from 'react' +import type { OutlineItem } from './markdown' +import { buildOutlineTree, collectBranchIds, type OutlineTreeNode } from './outlineTree' + +type Props = { + items: OutlineItem[] + onSelect: (item: OutlineItem) => void +} + +export function OutlinePanel({ items, onSelect }: Props): React.ReactElement { + const tree = React.useMemo(() => buildOutlineTree(items), [items]) + const branchIds = React.useMemo(() => collectBranchIds(tree), [tree]) + const [collapsed, setCollapsed] = React.useState>(() => new Set()) + + React.useEffect(() => { + setCollapsed(new Set()) + }, [items]) + + const toggleBranch = React.useCallback((id: string): void => { + setCollapsed((prev) => { + const next = new Set(prev) + if (next.has(id)) next.delete(id) + else next.add(id) + return next + }) + }, []) + + const expandAll = React.useCallback((): void => { + setCollapsed(new Set()) + }, []) + + const collapseAll = React.useCallback((): void => { + setCollapsed(new Set(branchIds)) + }, [branchIds]) + + const renderNode = (node: OutlineTreeNode): React.ReactElement => { + const hasChildren = node.children.length > 0 + const isCollapsed = collapsed.has(node.id) + + return ( +
  • +
    + {hasChildren ? ( + + ) : ( + + )} + +
    + {hasChildren && !isCollapsed ? ( +
      {node.children.map(renderNode)}
    + ) : null} +
  • + ) + } + + if (items.length === 0) { + return

    当前文档没有标题

    + } + + const collapsedCount = collapsed.size + const branchCount = branchIds.length + + return ( +
    +
    + + 大纲 + {branchCount > 0 ? ( + + {' '} + · {branchCount - collapsedCount}/{branchCount} 已展开 + + ) : null} + + + +
    +
      {tree.map(renderNode)}
    +
    + ) +} diff --git a/src/renderer/src/PreviewArticle.tsx b/src/renderer/src/PreviewArticle.tsx new file mode 100644 index 0000000..b1094d9 --- /dev/null +++ b/src/renderer/src/PreviewArticle.tsx @@ -0,0 +1,230 @@ +import * as React from 'react' +import mermaid from 'mermaid' + +let mermaidInited = false +let mermaidSeq = 0 + +function ensureMermaid(): void { + if (mermaidInited) return + mermaid.initialize({ + startOnLoad: false, + theme: 'neutral', + securityLevel: 'loose', + fontFamily: 'inherit', + flowchart: { useMaxWidth: true, htmlLabels: true }, + sequence: { useMaxWidth: true, wrap: true }, + er: { useMaxWidth: true }, + gantt: { useMaxWidth: true } + }) + mermaidInited = true +} + +function mermaidSourceFromWrap(wrap: HTMLElement): string { + const enc = wrap.getAttribute('data-mermaid-src') + if (enc) { + try { + return decodeURIComponent(enc) + } catch { + /* fall through */ + } + } + const pre = wrap.querySelector('pre.mermaid') + return pre?.textContent ?? '' +} + +async function renderMermaidIn(root: HTMLElement, isStale: () => boolean): Promise { + const wraps = root.querySelectorAll('.md-diagram-wrap') + if (wraps.length === 0) return + + ensureMermaid() + + for (const wrap of wraps) { + if (isStale()) return + + const source = mermaidSourceFromWrap(wrap).trim() + if (!source) continue + + delete wrap.dataset.mermaidRendered + + let host = wrap.querySelector('.mermaid-render-host') + const pre = wrap.querySelector('pre.mermaid') + if (pre) { + host = document.createElement('div') + host.className = 'mermaid-render-host' + pre.replaceWith(host) + } else if (!host) { + host = document.createElement('div') + host.className = 'mermaid-render-host' + wrap.appendChild(host) + } + + host.innerHTML = '
    ' + host.removeAttribute('data-mermaid-error') + + const id = `mr-mmd-${++mermaidSeq}` + try { + const { svg, bindFunctions } = await mermaid.render(id, source) + if (isStale()) return + if (!root.isConnected || !wrap.isConnected) return + host.innerHTML = svg + bindFunctions?.(host) + wrap.dataset.mermaidRendered = '1' + } catch (err) { + if (isStale()) return + const msg = err instanceof Error ? err.message : String(err) + host.setAttribute('data-mermaid-error', msg) + host.innerHTML = `
    ${escapeHtml(msg)}\n\n${escapeHtml(source.slice(0, 2000))}
    ` + console.warn("[Huangzhijun's Reader] mermaid render failed", err) + } + } +} + +function escapeHtml(s: string): string { + return s + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') +} + +function isMarkdownPath(p: string): boolean { + return /\.(md|markdown|mdown|mkd)$/i.test(p) +} + +function linkHref(anchor: HTMLAnchorElement): string | null { + return anchor.getAttribute('href') ?? anchor.getAttribute('data-md-href') +} + +type Props = { + html: string + articleRef?: React.Ref + baseFilePath?: string | null + resolveRelativePath?: (baseFilePath: string, href: string) => Promise + onOpenMarkdown?: (absolutePath: string, anchorId?: string) => void | Promise + onOpenExternal?: (url: string) => void | Promise +} + +export function PreviewArticle({ + html, + articleRef, + baseFilePath, + resolveRelativePath, + onOpenMarkdown, + onOpenExternal +}: Props): React.ReactElement { + const innerRef = React.useRef(null) + const renderGenRef = React.useRef(0) + const baseFilePathRef = React.useRef(baseFilePath) + baseFilePathRef.current = baseFilePath + const resolveRef = React.useRef(resolveRelativePath) + resolveRef.current = resolveRelativePath + const openMdRef = React.useRef(onOpenMarkdown) + openMdRef.current = onOpenMarkdown + const openExtRef = React.useRef(onOpenExternal) + openExtRef.current = onOpenExternal + + const setRef = React.useCallback( + (el: HTMLElement | null) => { + innerRef.current = el + if (typeof articleRef === 'function') articleRef(el) + else if (articleRef && typeof articleRef === 'object' && 'current' in articleRef) { + ;(articleRef as React.MutableRefObject).current = el + } + }, + [articleRef] + ) + + const scrollToAnchor = React.useCallback((root: HTMLElement, anchorId: string): void => { + const id = decodeURIComponent(anchorId) + if (!id) return + let el: Element | null = null + try { + el = root.querySelector(`#${CSS.escape(id)}`) + } catch { + el = root.querySelector(`#${id}`) + } + if (!el) el = document.getElementById(id) + el?.scrollIntoView({ behavior: 'smooth', block: 'start' }) + }, []) + + const handleClickCapture = React.useCallback((e: React.MouseEvent) => { + if (e.defaultPrevented || e.button !== 0) return + if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return + + const root = innerRef.current + if (!root) return + + const anchor = (e.target as Element | null)?.closest('a') + if (!anchor || !root.contains(anchor)) return + + const href = linkHref(anchor) + if (!href) return + + e.preventDefault() + e.stopPropagation() + + void (async () => { + if (href.startsWith('#')) { + scrollToAnchor(root, href.slice(1)) + return + } + + const hashIdx = href.indexOf('#') + const pathPart = (hashIdx >= 0 ? href.slice(0, hashIdx) : href).trim() + const anchorId = hashIdx >= 0 ? href.slice(hashIdx + 1) : '' + if (!pathPart) { + if (anchorId) scrollToAnchor(root, anchorId) + return + } + + if (/^https?:\/\//i.test(pathPart) || /^mailto:/i.test(pathPart) || /^tel:/i.test(pathPart)) { + await openExtRef.current?.(pathPart) + return + } + + const base = baseFilePathRef.current + if (!base) { + window.alert('请先保存当前文件,再打开文内相对链接。') + return + } + + const resolve = resolveRef.current + if (!resolve) return + + const resolved = await resolve(base, pathPart) + if (!resolved) return + + if (/^https?:\/\//i.test(resolved) || /^mailto:/i.test(resolved) || /^tel:/i.test(resolved)) { + await openExtRef.current?.(resolved) + return + } + + if (isMarkdownPath(resolved)) { + await openMdRef.current?.(resolved, anchorId || undefined) + return + } + + window.alert(`暂不支持打开该类型链接:${resolved}`) + })() + }, [scrollToAnchor]) + + React.useLayoutEffect(() => { + const root = innerRef.current + if (!root) return + + const gen = ++renderGenRef.current + root.innerHTML = html + + void renderMermaidIn(root, () => gen !== renderGenRef.current).catch((err) => { + console.warn("[Huangzhijun's Reader] mermaid batch failed", err) + }) + + return () => { + renderGenRef.current += 1 + } + }, [html]) + + return ( +
    + ) +} diff --git a/src/renderer/src/appearance-styles.css b/src/renderer/src/appearance-styles.css new file mode 100644 index 0000000..1f56ca8 --- /dev/null +++ b/src/renderer/src/appearance-styles.css @@ -0,0 +1,493 @@ +/* 背景(12):颜色变量,挂到 document.documentElement data-bg */ +:root[data-bg='0'] { + --app-bg: #f3f4f6; + --panel-bg: #e5e7eb; + --text: #111827; + --muted: #6b7280; + --border: #d1d5db; + --accent: #2563eb; + --btn-bg: #ffffff; + --hover: rgba(0, 0, 0, 0.06); + --preview-bg: #ffffff; + --preview-text: #111827; + --preview-shadow: 0 8px 30px rgba(15, 23, 42, 0.08); + --code-bg: #f9fafb; +} +:root[data-bg='1'] { + --app-bg: #f4ecd8; + --panel-bg: #e8dfc8; + --text: #3e3428; + --muted: #7a6a58; + --border: #d2c7b2; + --accent: #8b4513; + --btn-bg: #fffaf0; + --hover: rgba(62, 52, 40, 0.08); + --preview-bg: #fffaf0; + --preview-text: #3e3428; + --preview-shadow: 0 8px 24px rgba(62, 52, 40, 0.12); + --code-bg: #f0e6d6; +} +:root[data-bg='2'] { + --app-bg: #0f172a; + --panel-bg: #111c33; + --text: #e5e7eb; + --muted: #94a3b8; + --border: #1e293b; + --accent: #38bdf8; + --btn-bg: #1e293b; + --hover: rgba(148, 163, 184, 0.12); + --preview-bg: #111827; + --preview-text: #e5e7eb; + --preview-shadow: 0 12px 40px rgba(0, 0, 0, 0.45); + --code-bg: #0b1224; +} +:root[data-bg='3'] { + --app-bg: #102216; + --panel-bg: #143220; + --text: #e7f7ec; + --muted: #8fb39a; + --border: #1f3b2a; + --accent: #4ade80; + --btn-bg: #163527; + --hover: rgba(74, 222, 128, 0.12); + --preview-bg: #132a1f; + --preview-text: #e7f7ec; + --preview-shadow: 0 10px 36px rgba(0, 0, 0, 0.45); + --code-bg: #0d1f16; +} +:root[data-bg='4'] { + --app-bg: linear-gradient(160deg, #e0f2fe 0%, #eef2ff 45%, #fdf4ff 100%); + --panel-bg: rgba(255, 255, 255, 0.72); + --text: #0f172a; + --muted: #475569; + --border: #cbd5f5; + --accent: #4f46e5; + --btn-bg: rgba(255, 255, 255, 0.9); + --hover: rgba(79, 70, 229, 0.1); + --preview-bg: rgba(255, 255, 255, 0.92); + --preview-text: #0f172a; + --preview-shadow: 0 12px 40px rgba(15, 23, 42, 0.12); + --code-bg: #f8fafc; +} +:root[data-bg='5'] { + --app-bg: #fafafa; + --panel-bg: #ffffff; + --text: #111111; + --muted: #737373; + --border: #e5e5e5; + --accent: #db2777; + --btn-bg: #ffffff; + --hover: rgba(219, 39, 119, 0.08); + --preview-bg: #ffffff; + --preview-text: #111111; + --preview-shadow: 0 10px 30px rgba(15, 23, 42, 0.06); + --code-bg: #f5f5f5; +} +:root[data-bg='6'] { + --app-bg: #121212; + --panel-bg: #1a1a1a; + --text: #fafafa; + --muted: #a3a3a3; + --border: #262626; + --accent: #f97316; + --btn-bg: #171717; + --hover: rgba(249, 115, 22, 0.15); + --preview-bg: #0a0a0a; + --preview-text: #fafafa; + --preview-shadow: 0 0 0 1px #262626; + --code-bg: #000000; +} +:root[data-bg='7'] { + --app-bg: #f5f3ff; + --panel-bg: #ede9fe; + --text: #312e81; + --muted: #6d28d9; + --border: #ddd6fe; + --accent: #7c3aed; + --btn-bg: #ffffff; + --hover: rgba(124, 58, 237, 0.1); + --preview-bg: #ffffff; + --preview-text: #312e81; + --preview-shadow: 0 10px 32px rgba(49, 46, 129, 0.12); + --code-bg: #f5f3ff; +} +:root[data-bg='8'] { + --app-bg: #1c1917; + --panel-bg: #292524; + --text: #fafaf9; + --muted: #a8a29e; + --border: #44403c; + --accent: #fbbf24; + --btn-bg: #292524; + --hover: rgba(251, 191, 36, 0.12); + --preview-bg: #1c1917; + --preview-text: #fafaf9; + --preview-shadow: 0 12px 40px rgba(0, 0, 0, 0.55); + --code-bg: #0c0a09; +} +:root[data-bg='9'] { + --app-bg: #1a1033; + --panel-bg: #221547; + --text: #f3e8ff; + --muted: #c4b5fd; + --border: #3b2a6b; + --accent: #a78bfa; + --btn-bg: #2a185f; + --hover: rgba(167, 139, 250, 0.15); + --preview-bg: #120c24; + --preview-text: #f3e8ff; + --preview-shadow: 0 14px 48px rgba(0, 0, 0, 0.55); + --code-bg: #0f0820; +} +:root[data-bg='10'] { + --app-bg: #e8f4fc; + --panel-bg: #d7eaf8; + --text: #0c4a6e; + --muted: #0369a1; + --border: #bae6fd; + --accent: #0284c7; + --btn-bg: #f0f9ff; + --hover: rgba(2, 132, 199, 0.12); + --preview-bg: #ffffff; + --preview-text: #0c4a6e; + --preview-shadow: 0 10px 28px rgba(12, 74, 110, 0.1); + --code-bg: #e0f2fe; +} +:root[data-bg='11'] { + --app-bg: #fdf2f4; + --panel-bg: #fce7eb; + --text: #881337; + --muted: #9f1239; + --border: #fbcfe8; + --accent: #db2777; + --btn-bg: #fff1f2; + --hover: rgba(219, 39, 119, 0.1); + --preview-bg: #ffffff; + --preview-text: #881337; + --preview-shadow: 0 10px 28px rgba(136, 19, 55, 0.08); + --code-bg: #ffe4e6; +} +:root[data-bg='12'] { + --app-bg: #18181b; + --panel-bg: #27272a; + --text: #fafafa; + --muted: #a1a1aa; + --border: #3f3f46; + --accent: #22d3ee; + --btn-bg: #27272a; + --hover: rgba(34, 211, 238, 0.12); + --preview-bg: #18181b; + --preview-text: #fafafa; + --preview-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); + --code-bg: #09090b; +} +:root[data-bg='13'] { + --app-bg: #ecfeff; + --panel-bg: #cffafe; + --text: #0e7490; + --muted: #0891b2; + --border: #a5f3fc; + --accent: #0d9488; + --btn-bg: #f0fdfa; + --hover: rgba(13, 148, 136, 0.12); + --preview-bg: #ffffff; + --preview-text: #134e4a; + --preview-shadow: 0 10px 28px rgba(8, 145, 178, 0.1); + --code-bg: #ccfbf1; +} +:root[data-bg='14'] { + --app-bg: #faf5f0; + --panel-bg: #ede4d8; + --text: #422006; + --muted: #92400e; + --border: #d6c4b0; + --accent: #b45309; + --btn-bg: #fffbeb; + --hover: rgba(180, 83, 9, 0.1); + --preview-bg: #fffbeb; + --preview-text: #422006; + --preview-shadow: 0 10px 28px rgba(66, 32, 6, 0.08); + --code-bg: #fef3c7; +} +:root[data-bg='15'] { + --app-bg: #f0fdfa; + --panel-bg: #ccfbf1; + --text: #115e59; + --muted: #0f766e; + --border: #99f6e4; + --accent: #0d9488; + --btn-bg: #ecfdf5; + --hover: rgba(13, 148, 136, 0.12); + --preview-bg: #ffffff; + --preview-text: #134e4a; + --preview-shadow: 0 10px 28px rgba(17, 94, 89, 0.08); + --code-bg: #d1fae5; +} +:root[data-bg='16'] { + --app-bg: #f5f3ff; + --panel-bg: #ede9fe; + --text: #4c1d95; + --muted: #6d28d9; + --border: #ddd6fe; + --accent: #7c3aed; + --btn-bg: #faf5ff; + --hover: rgba(124, 58, 237, 0.1); + --preview-bg: #ffffff; + --preview-text: #4c1d95; + --preview-shadow: 0 10px 28px rgba(76, 29, 149, 0.08); + --code-bg: #ede9fe; +} +:root[data-bg='17'] { + --app-bg: #faf8f5; + --panel-bg: #f3efe8; + --text: #44403c; + --muted: #78716c; + --border: #e7e5e4; + --accent: #d97706; + --btn-bg: #ffffff; + --hover: rgba(217, 119, 6, 0.1); + --preview-bg: #ffffff; + --preview-text: #44403c; + --preview-shadow: 0 10px 28px rgba(68, 64, 60, 0.08); + --code-bg: #f5f5f4; +} +:root[data-bg='18'] { + --app-bg: #1c1917; + --panel-bg: #292524; + --text: #fafaf9; + --muted: #a8a29e; + --border: #44403c; + --accent: #eab308; + --btn-bg: #292524; + --hover: rgba(234, 179, 8, 0.12); + --preview-bg: #1c1917; + --preview-text: #fafaf9; + --preview-shadow: 0 12px 40px rgba(0, 0, 0, 0.45); + --code-bg: #0c0a09; +} +:root[data-bg='19'] { + --app-bg: #fdf4f8; + --panel-bg: #fce7f3; + --text: #831843; + --muted: #be185d; + --border: #fbcfe8; + --accent: #db2777; + --btn-bg: #fff1f2; + --hover: rgba(219, 39, 119, 0.1); + --preview-bg: #ffffff; + --preview-text: #831843; + --preview-shadow: 0 10px 28px rgba(131, 24, 67, 0.08); + --code-bg: #ffe4e6; +} +:root[data-bg='20'] { + --app-bg: #f1f5f9; + --panel-bg: #e2e8f0; + --text: #1e293b; + --muted: #64748b; + --border: #cbd5e1; + --accent: #475569; + --btn-bg: #ffffff; + --hover: rgba(71, 85, 105, 0.12); + --preview-bg: #ffffff; + --preview-text: #1e293b; + --preview-shadow: 0 10px 28px rgba(30, 41, 59, 0.1); + --code-bg: #f8fafc; +} +:root[data-bg='21'] { + --app-bg: #ecfdf5; + --panel-bg: #d1fae5; + --text: #14532d; + --muted: #166534; + --border: #bbf7d0; + --accent: #15803d; + --btn-bg: #f0fdf4; + --hover: rgba(21, 128, 61, 0.12); + --preview-bg: #ffffff; + --preview-text: #14532d; + --preview-shadow: 0 10px 28px rgba(20, 83, 45, 0.08); + --code-bg: #dcfce7; +} + +/* Kindle 风格:暖灰纸面 + 轻微颗粒感(纯 CSS) */ +:root[data-bg='22'] { + --app-bg: #e8e2d8; + --panel-bg: rgba(245, 241, 234, 0.94); + --text: #2d2a26; + --muted: #6b6560; + --border: #c9c2b8; + --accent: #c2410c; + --btn-bg: #faf6ef; + --hover: rgba(194, 65, 12, 0.08); + --preview-bg: #f7f3eb; + --preview-text: #1f1c18; + --preview-shadow: 0 10px 28px rgba(45, 42, 38, 0.1); + --code-bg: #ede8df; +} + +/* 字体:仅字体栈 */ +:root[data-font='0'] { + --font-ui: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; + --font-editor: ui-monospace, Menlo, Consolas, monospace; + --font-preview: Georgia, 'Times New Roman', 'Noto Serif SC', serif; +} +:root[data-font='1'] { + --font-ui: Georgia, 'Times New Roman', serif; + --font-editor: Consolas, 'Courier New', monospace; + --font-preview: 'Palatino Linotype', Palatino, 'Noto Serif SC', serif; +} +:root[data-font='2'] { + --font-ui: system-ui, sans-serif; + --font-editor: 'JetBrains Mono', 'Fira Code', Consolas, monospace; + --font-preview: 'Source Serif 4', Cambria, Georgia, serif; +} +:root[data-font='3'] { + --font-ui: 'Microsoft YaHei', 'PingFang SC', sans-serif; + --font-editor: 'Sarasa Mono SC', Consolas, monospace; + --font-preview: 'Songti SC', SimSun, 'Noto Serif SC', serif; +} +:root[data-font='4'] { + --font-ui: 'IBM Plex Sans', system-ui, sans-serif; + --font-editor: 'IBM Plex Mono', Consolas, monospace; + --font-preview: 'IBM Plex Serif', Georgia, serif; +} +:root[data-font='5'] { + --font-ui: 'Helvetica Neue', Helvetica, Arial, sans-serif; + --font-editor: Menlo, Monaco, Consolas, monospace; + --font-preview: 'Helvetica Neue', Arial, sans-serif; +} +:root[data-font='6'] { + --font-ui: Verdana, Geneva, sans-serif; + --font-editor: 'Lucida Console', monospace; + --font-preview: Georgia, Cambria, serif; +} +:root[data-font='7'] { + --font-ui: 'Trebuchet MS', sans-serif; + --font-editor: 'Courier New', Courier, monospace; + --font-preview: 'Book Antiqua', Palatino, serif; +} +:root[data-font='8'] { + --font-ui: 'Segoe UI', system-ui, sans-serif; + --font-editor: 'Cascadia Code', 'Cascadia Mono', Consolas, monospace; + --font-preview: Constantia, 'Times New Roman', serif; +} +:root[data-font='9'] { + --font-ui: 'Segoe UI Variable', 'Segoe UI', sans-serif; + --font-editor: 'Cascadia Mono', Consolas, monospace; + --font-preview: 'Sitka Text', Georgia, serif; +} +:root[data-font='10'] { + --font-ui: 'Noto Sans SC', 'Microsoft YaHei', 'PingFang SC', sans-serif; + --font-editor: 'Noto Sans Mono CJK SC', 'Sarasa Mono SC', Consolas, monospace; + --font-preview: 'Noto Serif SC', 'Source Han Serif SC', SimSun, serif; +} +:root[data-font='11'] { + --font-ui: 'Hiragino Sans GB', 'Microsoft YaHei', system-ui, sans-serif; + --font-editor: ui-monospace, monospace; + --font-preview: 'STKaiti', KaiTi, 'Noto Serif SC', serif; +} +:root[data-font='12'] { + --font-ui: 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif; + --font-editor: 'Menlo', 'Monaco', Consolas, monospace; + --font-preview: 'Songti SC', SimSun, 'Noto Serif SC', serif; +} +:root[data-font='13'] { + --font-ui: 'Hiragino Sans GB', 'PingFang SC', sans-serif; + --font-editor: 'SF Mono', Menlo, Consolas, monospace; + --font-preview: 'Hiragino Mincho ProN', 'Songti SC', serif; +} +:root[data-font='14'] { + --font-ui: 'LXGW WenKai', 'KaiTi', 'Microsoft YaHei', sans-serif; + --font-editor: 'JetBrains Mono', Consolas, monospace; + --font-preview: 'LXGW WenKai', 'KaiTi', 'Noto Serif SC', serif; +} +:root[data-font='15'] { + --font-ui: 'HarmonyOS Sans', 'Microsoft YaHei', system-ui, sans-serif; + --font-editor: 'HarmonyOS Sans Mono', Consolas, monospace; + --font-preview: 'HarmonyOS Serif', 'Noto Serif SC', serif; +} +:root[data-font='16'] { + --font-ui: 'OPPO Sans', 'Microsoft YaHei', system-ui, sans-serif; + --font-editor: 'OPPO Sans Mono', Consolas, monospace; + --font-preview: 'Source Han Serif SC', SimSun, serif; +} +:root[data-font='17'] { + --font-ui: 'MiSans', 'Microsoft YaHei', system-ui, sans-serif; + --font-editor: 'MiSans Mono', Consolas, monospace; + --font-preview: 'Noto Serif SC', 'Source Han Serif SC', serif; +} +:root[data-font='18'] { + --font-ui: 'Alibaba PuHuiTi', 'Microsoft YaHei', sans-serif; + --font-editor: 'JetBrains Mono', Consolas, monospace; + --font-preview: 'Alibaba PuHuiTi', 'Noto Serif SC', serif; +} +:root[data-font='19'] { + --font-ui: 'Smiley Sans', 'Microsoft YaHei', sans-serif; + --font-editor: 'JetBrains Mono', Consolas, monospace; + --font-preview: 'Smiley Sans', 'Noto Serif SC', serif; +} +:root[data-font='20'] { + --font-ui: system-ui, sans-serif; + --font-editor: 'Maple Mono', 'Cascadia Code', Consolas, monospace; + --font-preview: 'Source Serif 4', Georgia, serif; +} +:root[data-font='21'] { + --font-ui: 'Fira Sans', system-ui, sans-serif; + --font-editor: 'Fira Code', 'Fira Mono', Consolas, monospace; + --font-preview: 'Fira Sans', Georgia, serif; +} +:root[data-font='22'] { + --font-ui: 'Roboto', system-ui, sans-serif; + --font-editor: 'Roboto Mono', Consolas, monospace; + --font-preview: 'Roboto Slab', Georgia, serif; +} +:root[data-font='23'] { + --font-ui: 'Open Sans', system-ui, sans-serif; + --font-editor: 'Source Code Pro', Consolas, monospace; + --font-preview: 'Merriweather', Georgia, serif; +} +:root[data-font='24'] { + --font-ui: 'Lato', system-ui, sans-serif; + --font-editor: 'Ubuntu Mono', Consolas, monospace; + --font-preview: 'Lora', Georgia, serif; +} +:root[data-font='25'] { + --font-ui: 'Montserrat', system-ui, sans-serif; + --font-editor: 'Space Mono', Consolas, monospace; + --font-preview: 'Playfair Display', Georgia, serif; +} +:root[data-font='26'] { + --font-ui: 'Merriweather Sans', system-ui, sans-serif; + --font-editor: 'Inconsolata', Consolas, monospace; + --font-preview: 'Merriweather', Georgia, serif; +} +:root[data-font='27'] { + --font-ui: system-ui, sans-serif; + --font-editor: 'Source Code Pro', monospace; + --font-preview: 'Crimson Text', 'Times New Roman', serif; +} +:root[data-font='28'] { + --font-ui: 'Literata', Georgia, serif; + --font-editor: 'IBM Plex Mono', Consolas, monospace; + --font-preview: 'Literata', Georgia, serif; +} +:root[data-font='29'] { + --font-ui: system-ui, sans-serif; + --font-editor: 'Inconsolata', 'Consolas', monospace; + --font-preview: Georgia, 'Noto Serif SC', serif; +} +:root[data-font='30'] { + --font-ui: system-ui, sans-serif; + --font-editor: 'Anonymous Pro', 'Courier New', monospace; + --font-preview: 'Palatino Linotype', Palatino, serif; +} +:root[data-font='31'] { + --font-ui: system-ui, sans-serif; + --font-editor: 'Fantasque Sans Mono', Consolas, monospace; + --font-preview: 'Charter', 'Noto Serif SC', serif; +} + +:root[data-bg='4'] .toolbar, +:root[data-bg='4'] .tab-bar, +:root[data-bg='4'] .sidebar { + backdrop-filter: blur(8px); +} diff --git a/src/renderer/src/appearance.ts b/src/renderer/src/appearance.ts new file mode 100644 index 0000000..c417292 --- /dev/null +++ b/src/renderer/src/appearance.ts @@ -0,0 +1,74 @@ +/** 背景 id 0–22,对应 `appearance-styles.css` 中 `:root[data-bg]`。 */ +export const BACKGROUNDS: { id: string; name: string }[] = [ + { id: '0', name: '云雾灰' }, + { id: '1', name: '羊皮纸' }, + { id: '2', name: '深海蓝' }, + { id: '3', name: '森绿' }, + { id: '4', name: '极光渐变' }, + { id: '5', name: '极简粉' }, + { id: '6', name: '暗夜橙' }, + { id: '7', name: '薰衣草' }, + { id: '8', name: '暖石褐' }, + { id: '9', name: '星夜紫' }, + { id: '10', name: '霜青' }, + { id: '11', name: '玫瑰灰' }, + { id: '12', name: '石墨黑' }, + { id: '13', name: '薄荷冰' }, + { id: '14', name: '焦糖拿铁' }, + { id: '15', name: '青瓷' }, + { id: '16', name: '暮光紫灰' }, + { id: '17', name: '沙岸米' }, + { id: '18', name: '松烟墨' }, + { id: '19', name: '樱粉雾' }, + { id: '20', name: '钢蓝灰' }, + { id: '21', name: '苔痕绿' }, + { id: '22', name: 'Kindle 纸感' } +] + +/** 字体 id 0–31,对应 `:root[data-font]`。 */ +export const FONTS: { id: string; name: string }[] = [ + { id: '0', name: '系统默认' }, + { id: '1', name: '衬线阅读' }, + { id: '2', name: '等宽代码' }, + { id: '3', name: '人文宋黑' }, + { id: '4', name: 'IBM Plex' }, + { id: '5', name: 'Helvetica 系' }, + { id: '6', name: 'Georgia 系' }, + { id: '7', name: 'Verdana 系' }, + { id: '8', name: 'Courier 打字机' }, + { id: '9', name: 'Segoe UI 系' }, + { id: '10', name: '思源黑体优先' }, + { id: '11', name: '圆体休闲' }, + { id: '12', name: '苹方优先' }, + { id: '13', name: '冬青黑体' }, + { id: '14', name: '霞鹜文楷' }, + { id: '15', name: 'HarmonyOS Sans' }, + { id: '16', name: 'OPPO Sans' }, + { id: '17', name: '小米兰亭' }, + { id: '18', name: '阿里巴巴普惠' }, + { id: '19', name: '得意黑' }, + { id: '20', name: 'Maple Mono' }, + { id: '21', name: 'Fira Sans + Mono' }, + { id: '22', name: 'Roboto 系' }, + { id: '23', name: 'Open Sans 系' }, + { id: '24', name: 'Lato 系' }, + { id: '25', name: 'Montserrat 系' }, + { id: '26', name: 'Merriweather 阅读' }, + { id: '27', name: 'Crimson Text' }, + { id: '28', name: 'Literata 阅读' }, + { id: '29', name: 'Inconsolata 等宽' }, + { id: '30', name: 'Anonymous Pro' }, + { id: '31', name: 'Fantasque Sans Mono' } +] + +export type ViewMode = 'edit' | 'read' | 'hybrid' + +export function validBackgroundId(s: string | null): string | null { + if (s === null) return null + return /^([0-9]|1[0-9]|2[0-2])$/.test(s) ? s : null +} + +export function validFontId(s: string | null): string | null { + if (s === null) return null + return /^([0-9]|[12][0-9]|3[01])$/.test(s) ? s : null +} diff --git a/src/renderer/src/colorPresets.ts b/src/renderer/src/colorPresets.ts new file mode 100644 index 0000000..3aacf29 --- /dev/null +++ b/src/renderer/src/colorPresets.ts @@ -0,0 +1,11 @@ +/** 颜色选择器预设(按行分组展示) */ +export const COLOR_SWATCH_ROWS: string[][] = [ + ['#000000', '#1c1917', '#292524', '#44403c', '#57534e', '#78716c', '#a8a29e', '#d6d3d1'], + ['#450a0a', '#7f1d1d', '#b91c1c', '#dc2626', '#f87171', '#fecaca', '#fee2e2', '#fef2f2'], + ['#431407', '#9a3412', '#c2410c', '#ea580c', '#fb923c', '#fed7aa', '#ffedd5', '#fff7ed'], + ['#422006', '#a16207', '#ca8a04', '#eab308', '#fde047', '#fef9c3', '#fefce8', '#fefce8'], + ['#14532d', '#166534', '#15803d', '#22c55e', '#86efac', '#bbf7d0', '#dcfce7', '#f0fdf4'], + ['#134e4a', '#0f766e', '#0d9488', '#14b8a6', '#5eead4', '#ccfbf1', '#ecfdf5', '#f0fdfa'], + ['#1e3a8a', '#1d4ed8', '#2563eb', '#3b82f6', '#93c5fd', '#bfdbfe', '#dbeafe', '#eff6ff'], + ['#4c1d95', '#6d28d9', '#7c3aed', '#8b5cf6', '#c4b5fd', '#ddd6fe', '#ede9fe', '#f5f3ff'] +] diff --git a/src/renderer/src/env.d.ts b/src/renderer/src/env.d.ts new file mode 100644 index 0000000..cb27bb0 --- /dev/null +++ b/src/renderer/src/env.d.ts @@ -0,0 +1,36 @@ +/// + +import type { + ListDirResult, + OpenFileResult, + OpenFolderResult, + OpenImageResult, + SaveDialogResult +} from '../../../electron/ipc-types' + +export interface MyReaderApi { + openFileDialog: () => Promise + openFolderDialog: () => Promise + openImageDialog: () => Promise + saveFileDialog: (defaultPath?: string) => Promise + readFile: (filePath: string) => Promise + writeFile: (filePath: string, content: string) => Promise + listDirectory: (dirPath: string) => Promise + parentDirectory: (dirPath: string) => Promise + resolveRelativePath: (baseFilePath: string, href: string) => Promise + openExternal: (url: string) => Promise + defaultDirectory: () => Promise + deleteFile: (filePath: string) => Promise + renamePath: (oldPath: string, newName: string) => Promise<{ newPath: string }> + allowClose: () => void + onRequestClose: (handler: () => void) => () => void + onMenuAction: (handler: (action: string) => void) => () => void +} + +declare global { + interface Window { + myreader?: MyReaderApi + } +} + +export {} diff --git a/src/renderer/src/fileHistory.ts b/src/renderer/src/fileHistory.ts new file mode 100644 index 0000000..f918d03 --- /dev/null +++ b/src/renderer/src/fileHistory.ts @@ -0,0 +1,35 @@ +const HISTORY_KEY = 'myreader-file-history-v1' +const MAX_ITEMS = 80 + +export function loadFileHistory(): string[] { + try { + const raw = localStorage.getItem(HISTORY_KEY) + if (!raw) return [] + const data = JSON.parse(raw) as { paths?: unknown } + if (!Array.isArray(data.paths)) return [] + return data.paths.filter((p): p is string => typeof p === 'string' && p.length > 0) + } catch { + return [] + } +} + +export function saveFileHistory(paths: string[]): void { + localStorage.setItem(HISTORY_KEY, JSON.stringify({ v: 1, paths })) +} + +export function addFileHistory(paths: string[], filePath: string): string[] { + const next = [filePath, ...paths.filter((p) => p !== filePath)].slice(0, MAX_ITEMS) + saveFileHistory(next) + return next +} + +export function removeFileHistory(paths: string[], filePath: string): string[] { + const next = paths.filter((p) => p !== filePath) + saveFileHistory(next) + return next +} + +export function historyFileName(path: string): string { + const parts = path.split(/[/\\]/) + return parts[parts.length - 1] || path +} diff --git a/src/renderer/src/index.css b/src/renderer/src/index.css new file mode 100644 index 0000000..33b4334 --- /dev/null +++ b/src/renderer/src/index.css @@ -0,0 +1,1513 @@ +*, +*::before, +*::after { + box-sizing: border-box; +} + +html, +body, +#root { + height: 100%; + margin: 0; + overflow: hidden; + background: var(--app-bg, #e5e7eb); + color: var(--text, #111827); +} + +body { + font-family: var(--font-ui, system-ui, sans-serif); +} + +.app-root { + height: 100%; + overflow: hidden; + display: flex; + flex-direction: column; + color: var(--text); + background: var(--app-bg); + font-family: var(--font-ui, system-ui, sans-serif); +} + +/* Kindle 纸感:叠在纯色底上,避免覆盖 index 中的 background 简写 */ +html[data-bg='22'] .app-root { + background-color: var(--app-bg); + background-image: repeating-linear-gradient( + 0deg, + transparent, + transparent 2px, + rgba(0, 0, 0, 0.014) 2px, + rgba(0, 0, 0, 0.014) 3px + ), + radial-gradient(ellipse 120% 90% at 50% -10%, rgba(255, 255, 255, 0.55) 0%, transparent 55%), + radial-gradient(ellipse 80% 60% at 100% 100%, rgba(0, 0, 0, 0.04) 0%, transparent 50%); +} + +.no-api { + padding: 24px; +} + +.tab-bar { + display: flex; + flex: 0 0 auto; + flex-wrap: nowrap; + align-items: stretch; + gap: 4px; + padding: 6px 8px 0; + border-bottom: 1px solid var(--border); + background: var(--panel-bg); + position: relative; + z-index: 30; + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: thin; +} + +.tab-bar::-webkit-scrollbar { + height: 6px; +} + +.tab-bar::-webkit-scrollbar-thumb { + background: color-mix(in srgb, var(--muted) 50%, transparent); + border-radius: 3px; +} + +.tab { + display: inline-flex; + flex: 0 0 auto; + align-items: stretch; + max-width: 320px; + border: 1px solid transparent; + border-bottom: none; + border-radius: 6px 6px 0 0; + background: transparent; + color: inherit; + overflow: hidden; +} + +.tab.active { + background: var(--app-bg); + border-color: var(--border); +} + +.tab-main { + flex: 1; + min-width: 0; + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 4px 6px 10px; + border: none; + background: transparent; + color: inherit; + cursor: pointer; + text-align: left; + overflow: hidden; +} + +.tab-close { + flex: 0 0 28px; + border: none; + background: transparent; + color: var(--muted); + cursor: pointer; + font-size: 16px; + line-height: 1; +} + +.tab-close:hover { + color: var(--text); + background: var(--hover); +} + +.tab-title { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 15px; + font-weight: 600; + letter-spacing: 0.01em; +} + +.tab.active .tab-title { + font-size: 16px; + font-weight: 700; +} + +.tab .dot { + color: var(--accent); + font-size: 18px; + line-height: 1; +} + +.toolbar { + display: flex; + flex: 0 0 auto; + flex-wrap: wrap; + gap: 8px; + align-items: center; + padding: 8px 10px; + border-bottom: 1px solid var(--border); + background: var(--panel-bg); + position: relative; + z-index: 120; + isolation: isolate; +} + +.toolbar button, +.sidebar-tabs button, +.path-row button, +.dir-item, +.outline-title, +.outline-level--branch { + font: inherit; + cursor: pointer; +} + +.toolbar button { + padding: 6px 10px; + border-radius: 6px; + border: 1px solid var(--border); + background: var(--btn-bg); + color: var(--text); +} + +.toolbar button:hover { + border-color: var(--accent); +} + +.toolbar-tail { + margin-left: auto; + display: flex; + flex-wrap: nowrap; + align-items: flex-end; + gap: 8px; + flex: 0 0 auto; +} + +.bg-select { + flex: 0 0 7.25rem; + width: 7.25rem; + display: flex; + flex-direction: column; + align-items: stretch; + gap: 3px; + margin-left: 0; + font-size: 11px; + color: var(--muted); +} + +.bg-select select, +.bg-select .toolbar-mini-input { + width: 100%; + min-width: 0; + box-sizing: border-box; + padding: 3px 6px; + border-radius: 6px; + border: 1px solid var(--border); + background: var(--btn-bg); + color: var(--text); + position: relative; + z-index: 130; + font: inherit; + font-size: 12px; +} + +.bg-select .toolbar-mini-input { + -moz-appearance: textfield; +} + +.bg-select .toolbar-mini-input::-webkit-outer-spin-button, +.bg-select .toolbar-mini-input::-webkit-inner-spin-button { + margin: 0; + -webkit-appearance: none; +} + +.main { + flex: 1; + min-height: 0; + display: flex; + position: relative; + overflow: hidden; +} + +.sidebar { + flex: 0 0 auto; + flex-shrink: 0; + align-self: stretch; + border-right: 1px solid var(--border); + background: var(--panel-bg); + display: flex; + flex-direction: column; + min-height: 0; + overflow: hidden; +} + +.sidebar-resize { + width: 5px; + cursor: col-resize; + flex: 0 0 5px; + background: transparent; +} + +.sidebar-resize:hover { + background: var(--accent); + opacity: 0.35; +} + +.sidebar-reopen { + flex: 0 0 22px; + width: 22px; + border: none; + border-right: 1px solid var(--border); + background: var(--panel-bg); + color: var(--text); + cursor: pointer; + font-size: 16px; +} + +.sidebar-reopen:hover { + background: var(--hover); +} + +.sidebar-tabs { + display: flex; + border-bottom: 1px solid var(--border); +} + +.sidebar-tabs button { + flex: 1; + padding: 8px; + border: none; + background: transparent; + color: var(--muted); + border-bottom: 2px solid transparent; +} + +.sidebar-tabs button.on { + color: var(--text); + border-bottom-color: var(--accent); +} + +.file-pane, +.outline { + flex: 1; + min-height: 0; + overflow: auto; +} + +.path-row { + display: flex; + flex-direction: row; + align-items: center; + gap: 8px; + padding: 8px; + border-bottom: 1px solid var(--border); + flex-wrap: wrap; +} + +.path-row-actions { + display: flex; + flex-direction: column; + gap: 4px; + flex-shrink: 0; +} + +.path-row-actions button { + width: 100%; + min-width: 5.5rem; + white-space: nowrap; +} + +.path-row button { + padding: 4px 8px; + border-radius: 4px; + border: 1px solid var(--border); + background: var(--btn-bg); + color: var(--text); +} + +.path-row button:disabled { + opacity: 0.45; + cursor: not-allowed; +} + +.path { + flex: 1; + font-size: 12px; + color: var(--muted); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dir-error { + padding: 8px; + color: #c62828; + font-size: 13px; +} + +.dir-list, +.outline { + list-style: none; + margin: 0; + padding: 4px 0; +} + +.dir-item { + width: 100%; + text-align: left; + padding: 6px 10px; + border: none; + background: transparent; + color: inherit; + display: flex; + align-items: center; + gap: 8px; +} + +.outline-title, +.outline-level--branch { + font: inherit; + cursor: pointer; +} + +.outline-entry { + display: flex; + align-items: stretch; + gap: 10px; + padding: 4px 8px 4px 6px; + border-radius: 8px; + transition: background 0.12s ease; +} + +.outline-entry:hover { + background: var(--hover); +} + +.outline-entry--folded .outline-title { + color: var(--muted); +} + +.outline-level { + flex: 0 0 auto; + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 30px; + height: 30px; + padding: 0 6px; + border-radius: 8px; + border: 2px solid var(--border); + background: var(--btn-bg); + color: var(--text); + font-weight: 700; + line-height: 1; + box-sizing: border-box; +} + +.outline-level--leaf { + cursor: default; + border-style: solid; + opacity: 0.92; +} + +.outline-level--branch { + position: relative; + border-color: var(--accent); + background: color-mix(in srgb, var(--accent) 12%, var(--btn-bg)); + color: var(--accent); +} + +.outline-level--branch::after { + content: ''; + position: absolute; + right: 4px; + bottom: 4px; + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--accent); + box-shadow: 0 0 0 2px var(--btn-bg); +} + +.outline-level--branch.outline-level--collapsed { + border-style: dashed; + background: var(--btn-bg); + color: var(--muted); + border-color: var(--muted); +} + +.outline-level--branch.outline-level--collapsed::after { + background: transparent; + border: 2px solid var(--muted); + box-shadow: none; +} + +.outline-level-num { + font-size: 14px; + font-variant-numeric: tabular-nums; +} + +.outline-level--h1 { + min-width: 34px; + height: 34px; + font-size: 15px; + border-width: 2px; +} + +.outline-level--h1 .outline-level-num { + font-size: 15px; +} + +.outline-level--h2 { + min-width: 32px; + height: 32px; +} + +.outline-level--h3 { + min-width: 30px; + height: 28px; + font-weight: 650; +} + +.outline-level--h3 .outline-level-num { + font-size: 13px; +} + +.outline-level--h4, +.outline-level--h5, +.outline-level--h6 { + min-width: 28px; + height: 26px; + font-weight: 600; + color: var(--muted); + border-color: color-mix(in srgb, var(--border) 90%, var(--muted)); +} + +.outline-level--h4 .outline-level-num, +.outline-level--h5 .outline-level-num, +.outline-level--h6 .outline-level-num { + font-size: 12px; +} + +.outline-title { + flex: 1; + min-width: 0; + text-align: left; + padding: 6px 4px 6px 0; + border: none; + background: transparent; + color: inherit; + line-height: 1.4; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + white-space: normal; + word-break: break-word; +} + +.outline-entry--h1 .outline-title { + font-weight: 650; + font-size: 14px; +} + +.outline-entry--h2 .outline-title { + font-weight: 600; + font-size: 13px; +} + +.outline-entry--h3 .outline-title { + font-weight: 550; + font-size: 13px; +} + +.outline-entry--h4 .outline-title, +.outline-entry--h5 .outline-title, +.outline-entry--h6 .outline-title { + font-weight: 500; + font-size: 12px; + color: var(--muted); +} + +.outline-panel { + padding: 6px 4px; +} + +.outline-panel-wrap { + display: flex; + flex-direction: column; + flex: 1; + min-height: 0; + overflow: hidden; +} + +.outline-pane { + padding: 0; + display: flex; + flex-direction: column; + flex: 1; + min-height: 0; + overflow: hidden; +} + +.outline-toolbar { + display: flex; + align-items: center; + gap: 6px; + padding: 8px 8px 6px; + border-bottom: 1px solid var(--border); + flex-shrink: 0; +} + +.outline-toolbar-title { + flex: 1; + font-size: 12px; + color: var(--muted); +} + +.outline-toolbar-btn { + padding: 3px 8px; + font-size: 11px; + border-radius: 4px; + border: 1px solid var(--border); + background: var(--btn-bg); + color: var(--text); + cursor: pointer; + font: inherit; +} + +.outline-toolbar-btn:hover:not(:disabled) { + border-color: var(--accent); +} + +.outline-toolbar-btn:disabled { + opacity: 0.45; + cursor: default; +} + +.outline-toolbar-meta { + color: var(--muted); + font-weight: 400; +} + +.outline-tree--root { + overflow: auto; + flex: 1; + min-height: 0; +} + +.outline-tree-row { + display: flex; + align-items: center; + gap: 4px; + min-width: 0; + padding: 2px 6px 2px 4px; + border-radius: 6px; +} + +.outline-tree-row:hover { + background: var(--hover); +} + +.outline-fold-btn { + flex: 0 0 22px; + width: 22px; + height: 22px; + padding: 0; + border: 1px solid var(--border); + border-radius: 4px; + background: var(--btn-bg); + color: var(--accent); + font-size: 12px; + line-height: 1; + cursor: pointer; + font: inherit; +} + +.outline-fold-btn:hover { + border-color: var(--accent); + background: color-mix(in srgb, var(--accent) 10%, var(--btn-bg)); +} + +.outline-fold-btn.is-collapsed { + color: var(--muted); +} + +.outline-fold-spacer { + flex: 0 0 22px; + width: 22px; +} + +.outline-tree-title { + flex: 1; + min-width: 0; + text-align: left; + border: none; + background: transparent; + color: var(--text); + font: inherit; + padding: 4px 6px; + border-radius: 4px; + cursor: pointer; + line-height: 1.35; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.outline-tree-title:hover { + color: var(--accent); +} + +.outline-tree-title--h1 { + font-weight: 700; + font-size: 14px; +} + +.outline-tree-title--h2 { + font-weight: 650; + font-size: 13.5px; +} + +.outline-tree-title--h3 { + font-weight: 600; + font-size: 13px; +} + +.outline-tree-title--h4, +.outline-tree-title--h5, +.outline-tree-title--h6 { + font-weight: 500; + font-size: 12.5px; + color: var(--muted); +} + +.outline-tree { + list-style: none; + margin: 0; + padding: 4px 0 8px; +} + +.outline-tree .outline-tree { + margin: 2px 0 4px 6px; + padding: 2px 0 2px 12px; + border-left: 2px solid color-mix(in srgb, var(--accent) 22%, var(--border)); +} + +.outline-tree-node { + margin: 0; +} + +.outline-empty { + margin: 12px 10px; + font-size: 13px; + color: var(--muted); +} + +.outline-simple { + list-style: none; + margin: 0; + padding: 6px 4px 10px; +} + +.outline-simple-item { + width: 100%; + text-align: left; + border: none; + background: transparent; + color: var(--text); + font: inherit; + padding: 6px 8px; + border-radius: 6px; + cursor: pointer; + line-height: 1.35; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.outline-simple-item:hover { + background: var(--hover); +} + +.outline-simple-item--h1 { + font-weight: 700; + font-size: 14px; +} + +.outline-simple-item--h2 { + font-weight: 650; + font-size: 13.5px; +} + +.outline-simple-item--h3 { + font-weight: 600; + font-size: 13px; + color: color-mix(in srgb, var(--text) 88%, var(--muted)); +} + +.outline-simple-item--h4, +.outline-simple-item--h5, +.outline-simple-item--h6 { + font-weight: 500; + font-size: 12.5px; + color: var(--muted); +} + +.history-pane { + padding-top: 4px; +} + +.history-list { + list-style: none; + margin: 0; + padding: 0 4px 8px; +} + +.history-item { + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 2px; + text-align: left; + border: none; + background: transparent; + color: inherit; + font: inherit; + padding: 8px 10px; + border-radius: 8px; + cursor: pointer; +} + +.history-item:hover { + background: var(--hover); +} + +.history-item-name { + font-weight: 600; + font-size: 13px; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.history-item-path { + font-size: 11px; + color: var(--muted); + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.entry-kind { + flex: 0 0 24px; + font-size: 10px; + font-weight: 700; + text-align: center; + border-radius: 4px; + padding: 3px 0; + line-height: 1.1; + color: #fff; +} + +.entry-kind--dir { + background: #4f46e5; +} + +.entry-kind--file { + background: #047857; +} + +.entry-name { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-align: left; +} + +.md-format-wrap { + width: 100%; + border-bottom: 1px solid var(--border); + background: var(--panel-bg); + position: relative; + z-index: 25; +} + +.md-format-bar { + display: flex; + flex-wrap: wrap; + gap: 4px; + padding: 6px 8px; + max-height: 120px; + overflow-y: auto; +} + +.md-format-bar button { + padding: 4px 8px; + font-size: 12px; + border-radius: 4px; + border: 1px solid var(--border); + background: var(--btn-bg); + color: var(--text); + cursor: pointer; + white-space: nowrap; +} + +.md-format-bar button:hover { + border-color: var(--accent); +} + +.dir-item[data-kind='dir'] { + font-weight: 600; +} + +.content { + flex: 1; + min-width: 0; + min-height: 0; + display: flex; + flex-direction: column; + position: relative; + z-index: 1; + overflow: hidden; +} + +.content-empty { + flex: 1; + min-height: 0; + display: flex; + align-items: center; + justify-content: center; + padding: 32px; + color: var(--muted); + font-size: 15px; + text-align: center; +} + +.editor-host { + flex: 1; + min-height: 0; +} + +.editor-host .cm-editor { + height: 100%; +} + +.preview-outer { + flex: 1; + min-height: 0; + overflow-y: auto; + overflow-x: hidden; + display: flex; + justify-content: center; + align-items: flex-start; + padding: 12px 16px 16px; +} + +.preview-shell { + position: relative; + flex: 0 1 auto; + min-width: 0; + width: 100%; +} + +.preview-shell--tight { + padding: 0 8px 8px; +} + +.preview-resizer { + position: absolute; + top: 0; + right: -10px; + width: 16px; + height: 100%; + cursor: ew-resize; + z-index: 5; + border-radius: 4px; + border: 2px solid var(--accent); + background: var(--btn-bg); + opacity: 0.95; +} + +.preview-resizer:hover { + opacity: 1; + filter: brightness(1.05); +} + +.preview-resizer::after { + content: '‖'; + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + color: var(--accent); + pointer-events: none; +} + +.preview { + flex: 0 0 auto; + overflow: visible; + padding: 24px 32px 48px; + width: 100%; + font-size: 16px; + line-height: var(--preview-line-height, 1.65); + background: var(--preview-bg); + color: var(--preview-text); + border-radius: 8px; + box-shadow: var(--preview-shadow); + font-family: var(--font-preview, var(--font-ui, Georgia, serif)); +} + +.preview code { + font-family: 'Cascadia Code', 'Consolas', 'Monaco', 'Courier New', monospace; + font-size: 0.9em; + background: color-mix(in srgb, var(--code-bg) 85%, var(--border)); + padding: 0.12em 0.35em; + border-radius: 4px; +} + +.preview .md-code-wrap { + position: relative; + margin: 1.1em 0; + border: 1px solid color-mix(in srgb, var(--border) 90%, #000); + border-radius: 6px; + background: var(--code-bg); + overflow: hidden; +} + +.preview .md-code-wrap .md-code-lang { + position: absolute; + top: 0; + right: 0; + padding: 3px 10px; + font-size: 11px; + color: var(--muted); + text-transform: lowercase; + letter-spacing: 0.02em; + pointer-events: none; + user-select: none; +} + +.preview .md-code-wrap pre.hljs { + margin: 0; + padding: 16px 18px; + background: transparent; + border-radius: 0; + overflow-x: auto; +} + +.preview .md-code-wrap pre.hljs code { + font-family: 'Cascadia Code', 'Consolas', 'Monaco', 'Courier New', monospace; + font-size: 13px; + line-height: 1.55; + background: transparent; + padding: 0; +} + +.preview .md-diagram-wrap { + margin: 1.5em 0; + padding: 20px 16px 24px; + background: var(--preview-bg); + border: 1px solid color-mix(in srgb, var(--border) 85%, #000); + border-radius: 6px; + overflow-x: auto; + overflow-y: hidden; + text-align: center; + contain: layout style; +} + +.preview .md-diagram-wrap pre.mermaid { + margin: 0; + padding: 0; + border: none; + background: transparent; + text-align: center; +} + +.preview .md-diagram-wrap .mermaid-render-host { + display: flex; + justify-content: center; + align-items: center; + min-height: 4rem; + width: 100%; + overflow: hidden; +} + +.preview .md-diagram-wrap .mermaid-placeholder { + min-height: 4rem; + width: 100%; +} + +.preview .md-diagram-wrap .mermaid-render-host svg { + max-width: 100%; + height: auto; + display: block; +} + +.preview .md-diagram-wrap .mermaid-error { + margin: 0; + padding: 12px; + text-align: left; + font-size: 12px; + color: #b91c1c; + background: color-mix(in srgb, #fecaca 40%, transparent); + border-radius: 4px; + white-space: pre-wrap; + word-break: break-word; +} + +.hybrid-preview .preview .md-diagram-wrap { + width: 100%; + min-width: 0; + box-sizing: border-box; +} + +.preview img { + max-width: 100%; + height: auto; + display: block; + margin: 1em auto; + border-radius: 6px; + box-shadow: 0 2px 12px rgba(15, 23, 42, 0.1); +} + +.preview h1, +.preview h2, +.preview h3, +.preview h4, +.preview h5, +.preview h6 { + font-family: inherit; + color: inherit; + margin-top: 1.25em; + margin-bottom: 0.55em; + line-height: 1.25; +} + +.preview h1 { + font-size: 2rem; + font-weight: 700; + margin-top: 0.35em; + padding-bottom: 0.2em; + border-bottom: 1px solid color-mix(in srgb, var(--border) 70%, transparent); +} + +.preview h2 { + font-size: 1.55rem; + font-weight: 650; +} + +.preview h3 { + font-size: 1.28rem; + font-weight: 600; +} + +.preview h4 { + font-size: 1.12rem; + font-weight: 600; +} + +.preview h5 { + font-size: 1.02rem; + font-weight: 600; +} + +.preview h6 { + font-size: 0.95rem; + font-weight: 600; + color: var(--muted); +} + +.preview pre { + overflow: auto; + padding: 12px; + border-radius: 6px; + background: var(--code-bg); +} + +.preview .hljs, +.preview .hljs code { + font-family: 'Cascadia Code', 'Consolas', 'Monaco', 'Courier New', monospace !important; +} + +.preview a { + color: #4183c4; + text-decoration: none; + cursor: pointer; +} + +.preview a:hover { + text-decoration: underline; +} + +.preview a.md-internal-link { + color: #4183c4; + border-bottom: 1px dashed color-mix(in srgb, #4183c4 55%, transparent); +} + +.preview a.md-internal-link:hover { + border-bottom-style: solid; +} + +.preview hr { + border: none; + border-top: 1px solid var(--border); + margin: 1.25em 0; + height: 0; + background: none; +} + +.hybrid-row { + flex: 1; + min-height: 0; + display: flex; + flex-direction: row; + align-items: stretch; +} + +.hybrid-editor { + min-width: 0; + min-height: 0; + display: flex; + flex-direction: column; + border-right: 1px solid var(--border); +} + +.hybrid-sash { + flex: 0 0 6px; + cursor: col-resize; + background: transparent; +} + +.hybrid-sash:hover { + background: var(--accent); + opacity: 0.25; +} + +.hybrid-preview { + flex: 1; + min-width: 0; + min-height: 0; + overflow: auto; + display: flex; + justify-content: center; +} + +.hybrid-preview-shell { + position: relative; +} + +.hybrid-line-pulse { + position: absolute; + left: 8px; + right: 8px; + height: 1.75em; + transform: translateY(-50%); + pointer-events: none; + z-index: 2; + border-radius: 6px; + background: rgba(250, 204, 21, 0.42); + box-shadow: 0 0 0 1px rgba(234, 179, 8, 0.35); + animation: hybrid-line-pulse 1.35s ease-in-out forwards; +} + +@keyframes hybrid-line-pulse { + 0%, + 100% { + opacity: 0; + } + 12%, + 30% { + opacity: 1; + } + 42% { + opacity: 0; + } + 54%, + 72% { + opacity: 1; + } + 84%, + 100% { + opacity: 0; + } +} + +.modal-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.35); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; +} + +.modal { + width: min(420px, calc(100% - 32px)); + background: var(--panel-bg); + color: var(--text); + border: 1px solid var(--border); + border-radius: 10px; + padding: 16px 18px; + box-shadow: var(--preview-shadow); +} + +.modal-title { + margin: 0 0 8px; + font-size: 16px; +} + +.modal-body { + margin: 0 0 16px; + font-size: 14px; + color: var(--muted); +} + +.modal-text-input { + width: 100%; + box-sizing: border-box; + margin: 0 0 16px; + padding: 8px 10px; + border-radius: 6px; + border: 1px solid var(--border); + background: var(--btn-bg); + color: var(--text); + font: inherit; +} + +.modal-actions { + display: flex; + flex-wrap: wrap; + gap: 8px; + justify-content: flex-end; +} + +.modal-actions button { + padding: 6px 12px; + border-radius: 6px; + border: 1px solid var(--border); + background: var(--btn-bg); + color: var(--text); + cursor: pointer; +} + +.modal-actions button.primary { + border-color: var(--accent); + background: var(--accent); + color: #fff; +} + +.modal--wide { + width: min(480px, calc(100% - 32px)); +} + +.modal-hint { + margin: 0 0 12px; + font-size: 13px; + color: var(--muted); + line-height: 1.45; +} + +.modal-field { + display: block; + margin-bottom: 12px; +} + +.modal-field .modal-text-input { + margin-bottom: 0; +} + +.modal-label { + display: block; + font-size: 12px; + color: var(--muted); + margin-bottom: 4px; +} + +.modal-row-btns { + margin: -4px 0 12px; +} + +.modal-row-btns button { + padding: 6px 12px; + border-radius: 6px; + border: 1px solid var(--border); + background: var(--btn-bg); + color: var(--text); + cursor: pointer; + font: inherit; +} + +.modal-row-btns button:hover { + border-color: var(--accent); +} + +.color-picker-native { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 12px; +} + +.color-picker-spectrum { + width: 56px; + height: 36px; + padding: 0; + border: 1px solid var(--border); + border-radius: 6px; + cursor: pointer; + background: var(--btn-bg); +} + +.color-swatch-grid { + display: flex; + flex-direction: column; + gap: 6px; + margin-bottom: 14px; +} + +.color-swatch-row { + display: flex; + gap: 6px; + flex-wrap: wrap; +} + +.color-swatch { + width: 22px; + height: 22px; + border-radius: 4px; + border: 2px solid var(--border); + padding: 0; + cursor: pointer; + box-sizing: border-box; +} + +.color-swatch:hover { + transform: scale(1.08); +} + +.color-swatch.selected { + border-color: var(--accent); + box-shadow: 0 0 0 1px var(--accent); +} + +.ctx-menu { + position: fixed; + z-index: 900; + min-width: 120px; + background: var(--panel-bg); + border: 1px solid var(--border); + border-radius: 6px; + box-shadow: var(--preview-shadow); + padding: 4px; +} + +.ctx-item { + width: 100%; + text-align: left; + border: none; + background: transparent; + color: var(--text); + padding: 8px 10px; + border-radius: 4px; + cursor: pointer; + font: inherit; +} + +.ctx-item.danger { + color: #b91c1c; +} + +.ctx-item:hover { + background: var(--hover); +} + +.preview .md-table-wrap { + overflow-x: auto; + margin: 1.25em 0; + border: 1px solid var(--border); + border-radius: 8px; + box-shadow: 0 1px 4px rgba(15, 23, 42, 0.06); +} + +.preview table { + width: 100%; + border-collapse: collapse; + font-size: 0.94em; + line-height: 1.55; +} + +.preview thead th { + background: color-mix(in srgb, var(--accent) 10%, var(--preview-bg)); + font-weight: 650; + text-align: left; + padding: 10px 14px; + border-bottom: 2px solid var(--border); + white-space: nowrap; +} + +.preview tbody td { + padding: 9px 14px; + border-bottom: 1px solid color-mix(in srgb, var(--border) 80%, transparent); + vertical-align: top; +} + +.preview tbody tr:nth-child(even) td { + background: color-mix(in srgb, var(--text) 3%, transparent); +} + +.preview tbody tr:hover td { + background: color-mix(in srgb, var(--accent) 7%, transparent); +} + +.preview tbody tr:last-child td { + border-bottom: none; +} + + +.preview pre.mermaid:not(.md-diagram-wrap pre.mermaid) { + margin: 1.5em 0; + padding: 18px 16px; + background: var(--code-bg); + border: 1px solid var(--border); + border-radius: 8px; + overflow: auto; + text-align: center; +} + +.preview-anchor-flash { + animation: preview-anchor-flash 1.4s ease-out; +} + +@keyframes preview-anchor-flash { + 0%, + 100% { + background-color: transparent; + box-shadow: none; + } + 15%, + 40% { + background-color: rgba(250, 204, 21, 0.35); + box-shadow: 0 0 0 2px rgba(234, 179, 8, 0.25); + border-radius: 4px; + } + 55% { + background-color: transparent; + box-shadow: none; + } + 70% { + background-color: rgba(250, 204, 21, 0.28); + box-shadow: 0 0 0 2px rgba(234, 179, 8, 0.2); + border-radius: 4px; + } +} diff --git a/src/renderer/src/main.tsx b/src/renderer/src/main.tsx new file mode 100644 index 0000000..f294a70 --- /dev/null +++ b/src/renderer/src/main.tsx @@ -0,0 +1,27 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import App from './App' +import { validBackgroundId, validFontId } from './appearance' +import './appearance-styles.css' +import './index.css' + +{ + const bg = + localStorage.getItem('myreader-bg-id') ?? + localStorage.getItem('myreader-theme') ?? + localStorage.getItem('myreader-bg') ?? + '1' + const font = localStorage.getItem('myreader-font-id') ?? '0' + const line = localStorage.getItem('myreader-preview-line-height') + const lineN = line ? Number.parseFloat(line) : NaN + const lineH = Number.isFinite(lineN) ? String(Math.min(3, Math.max(1, lineN))) : '1.5' + document.documentElement.dataset.bg = validBackgroundId(bg) ?? '1' + document.documentElement.dataset.font = validFontId(font) ?? '0' + document.documentElement.style.setProperty('--preview-line-height', lineH) +} + +createRoot(document.getElementById('root')!).render( + + + +) diff --git a/src/renderer/src/markdown.ts b/src/renderer/src/markdown.ts new file mode 100644 index 0000000..4e99f99 --- /dev/null +++ b/src/renderer/src/markdown.ts @@ -0,0 +1,406 @@ +import MarkdownIt from 'markdown-it' +import multimdTable from 'markdown-it-multimd-table' +import hljs from 'highlight.js' +import DOMPurify from 'dompurify' +import { absolutePathToFileUrl, resolvePathFromBaseFile } from './pathLite' +import 'highlight.js/styles/github.min.css' + +const MERMAID_LANG = new Set(['mermaid', 'flowchart', 'sequencediagram', 'sequence']) +const MERMAID_START = + /^\s*(sequenceDiagram|classDiagram|stateDiagram(?:-v2)?|erDiagram|gantt|pie|gitGraph|journey|flowchart\s|graph\s|mindmap|timeline|quadrantChart|xychart-beta|block-beta)/i + +function isMermaidFence(lang: string, content: string): boolean { + const l = lang.toLowerCase() + if (MERMAID_LANG.has(l)) return true + if (!lang.trim() && MERMAID_START.test(content)) return true + return false +} + +function highlightCodeBlock(content: string, lang: string): string { + const trimmed = (lang || '').trim() + if (trimmed && hljs.getLanguage(trimmed)) { + try { + return hljs.highlight(content, { language: trimmed, ignoreIllegals: true }).value + } catch { + /* fall through */ + } + } + if (trimmed) { + try { + return hljs.highlightAuto(content).value + } catch { + /* fall through */ + } + } + return md.utils.escapeHtml(content) +} + +const md = new MarkdownIt({ + html: true, + linkify: true, + typographer: true, + highlight: function (this: MarkdownIt, str: string, lang: string) { + const body = highlightCodeBlock(str.replace(/\n$/, ''), lang) + return `
    ${body}
    ` + } +}) + +md.use(multimdTable, { multiline: true, rowspan: true, headerless: false }) + +/** 允许本地 file:// 图片与链接(markdown-it 默认禁止 file: 协议)。 */ +const defaultValidateLink = md.validateLink.bind(md) +md.validateLink = (url: string): boolean => { + if (/^file:/i.test(url)) return true + return defaultValidateLink(url) +} + +/** 禁用 Setext 标题,避免 `---` 等被当成 h2。 */ +md.disable(['lheading']) + +function setBlockSourceLines(token: { map?: [number, number] | null; attrSet: (n: string, v: string) => void }): void { + if (!token.map) return + const start = token.map[0] + const end = Math.max(start, token.map[1] - 1) + token.attrSet('data-source-line', String(start)) + token.attrSet('data-source-line-end', String(end)) +} + +const defaultHeadingOpen = + md.renderer.rules.heading_open ?? + function (tokens, idx, options, _env, self) { + return self.renderToken(tokens, idx, options) + } + +md.renderer.rules.heading_open = (tokens, idx, options, env, self) => { + const token = tokens[idx] + setBlockSourceLines(token) + token.attrSet('id', slugForLine(token.map ? token.map[0] : 0)) + return defaultHeadingOpen(tokens, idx, options, env, self) +} + +function wrapBlockOpenRule(ruleName: 'paragraph_open' | 'list_item_open' | 'blockquote_open'): void { + const prev = md.renderer.rules[ruleName] + md.renderer.rules[ruleName] = (tokens, idx, options, env, self) => { + setBlockSourceLines(tokens[idx]!) + if (prev) return prev(tokens, idx, options, env, self) + return self.renderToken(tokens, idx, options) + } +} + +wrapBlockOpenRule('paragraph_open') +wrapBlockOpenRule('list_item_open') +wrapBlockOpenRule('blockquote_open') + +const defaultTableOpen = md.renderer.rules.table_open +const defaultTableClose = md.renderer.rules.table_close + +md.renderer.rules.table_open = (tokens, idx, options, env, self) => { + setBlockSourceLines(tokens[idx]!) + const inner = defaultTableOpen + ? defaultTableOpen(tokens, idx, options, env, self) + : '' + return `
    ${inner}` +} + +md.renderer.rules.table_close = (tokens, idx, options, env, self) => { + const inner = defaultTableClose + ? defaultTableClose(tokens, idx, options, env, self) + : '
    ' + return `${inner}
    ` +} + +function normalizeImageSrc(src: string, baseFilePath: string | null | undefined): string { + const s = src.trim() + if (!s) return s + if (/^file:\/\//i.test(s)) return s + if (/^https?:\/\//i.test(s) || /^data:/i.test(s)) return s + if (baseFilePath?.trim()) { + try { + let pathPart = s + if (pathPart.startsWith('file:')) { + pathPart = pathPart.replace(/^file:\/*/i, '') + try { + pathPart = decodeURIComponent(pathPart) + } catch { + /* keep */ + } + } + const abs = resolvePathFromBaseFile(baseFilePath, pathPart) + return absolutePathToFileUrl(abs) + } catch { + /* keep */ + } + } + return s +} + +const defaultImage = md.renderer.rules.image! +md.renderer.rules.image = (tokens, idx, options, env, self) => { + const token = tokens[idx]! + const src = token.attrGet('src') + const base = (env as { baseFilePath?: string | null }).baseFilePath + if (src) { + token.attrSet('src', normalizeImageSrc(src, base)) + } + const html = defaultImage(tokens, idx, options, env, self) + return html.replace(/ { + const token = tokens[idx] + if (!token.map) { + return defaultFence ? defaultFence(tokens, idx, options, env, self) : '' + } + const lang = (token.info || '').trim() + const raw = token.content.replace(/\n$/, '') + const codeEndLine = Math.max(token.map[0], token.map[1] - 1) + + if (isMermaidFence(lang, raw)) { + const trimmed = raw.trim() + const escaped = md.utils.escapeHtml(trimmed) + const dataSrc = md.utils.escapeHtml(encodeURIComponent(trimmed)) + return `
    ${escaped}
    ` + } + + const highlighted = highlightCodeBlock(raw, lang) + const langLabel = lang + ? `${md.utils.escapeHtml(lang.split(/\s+/)[0] ?? lang)}` + : '' + return `
    ${langLabel}
    ${highlighted}
    ` +} + +const purifyOpts: Parameters[1] = { + USE_PROFILES: { html: true }, + ADD_TAGS: ['span', 'mark', 'kbd', 'sup', 'sub', 'details', 'summary', 'font', 'div'], + ADD_ATTR: [ + 'style', + 'color', + 'open', + 'data-source-line', + 'data-source-line-end', + 'id', + 'class', + 'href', + 'data-md-href', + 'src', + 'alt', + 'width', + 'height', + 'loading', + 'decoding', + 'data-mermaid-src' + ], + ALLOWED_URI_REGEXP: + /^(?:(?:https?|mailto|tel|data|file):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i +} + +const defaultLinkOpen = md.renderer.rules.link_open +md.renderer.rules.link_open = (tokens, idx, options, env, self) => { + const token = tokens[idx]! + const href = token.attrGet('href') ?? '' + if (href && !/^https?:\/\//i.test(href) && !href.startsWith('#') && !href.startsWith('mailto:')) { + token.attrSet('class', 'md-internal-link') + token.attrSet('data-md-href', href) + } + if (defaultLinkOpen) return defaultLinkOpen(tokens, idx, options, env, self) + return self.renderToken(tokens, idx, options) +} + +export function slugForLine(line: number): string { + return `mr-line-${line}` +} + +export type RenderMarkdownEnv = { + baseFilePath?: string | null +} + +export function renderMarkdown(src: string, env?: RenderMarkdownEnv): string { + const input = typeof src === 'string' ? src : '' + const renderEnv = env ?? {} + try { + const raw = md.render(input, renderEnv) + try { + return DOMPurify.sanitize(raw, purifyOpts) + } catch (e) { + console.warn('[MyReader] DOMPurify failed', e) + return `

    ${md.utils.escapeHtml(raw.slice(0, 8000))}

    ` + } + } catch (e) { + console.warn('[MyReader] markdown render failed', e) + return `
    ${md.utils.escapeHtml(input.slice(0, 8000))}
    ` + } +} + +export type OutlineItem = { + level: number + text: string + displayText: string + /** 0-based source line */ + line: number + slug: string +} + +function outlineDisplayText(raw: string): string { + let s = raw + s = s.replace(/\*\*([^*]+)\*\*/g, '$1') + s = s.replace(/\*([^*]+)\*/g, '$1') + s = s.replace(/`([^`]+)`/g, '$1') + s = s.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1') + s = s.replace(/<[^>]+>/g, '') + s = s.replace(/\s+/g, ' ').trim() + return s +} + +/** 分隔线、纯符号等不应出现在大纲。 */ +export function isValidOutlineHeading(displayText: string, rawLine: string): boolean { + const t = displayText.trim() + if (!t || t === '(空标题)') return false + if (/^[-—–_=~*`#>\s]+$/.test(t)) return false + const body = rawLine.replace(/^#{1,6}\s*/, '').trim() + if (/^[-—–_=~*\s]+$/.test(body)) return false + return true +} + +/** 仅从 ATX `#` 标题提取;`line` 为 0-based。 */ +export function extractOutline(src: string): OutlineItem[] { + const input = typeof src === 'string' ? src : '' + const lines = input.split(/\r?\n/) + const out: OutlineItem[] = [] + for (let i = 0; i < lines.length; i++) { + const raw = lines[i] ?? '' + const m = /^(#{1,6})\s+(.+)$/.exec(raw) + if (!m) continue + const level = m[1]!.length + const text = m[2]!.trim() + const displayText = outlineDisplayText(text) || '(空标题)' + if (!isValidOutlineHeading(displayText, raw)) continue + out.push({ + level, + text, + displayText, + line: i, + slug: slugForLine(i) + }) + } + return out +} + +export type SourceLineRegion = { + line: number + lineEnd: number + el: HTMLElement +} + +export function collectSourceLineRegions(article: HTMLElement): SourceLineRegion[] { + const nodes = article.querySelectorAll('[data-source-line]') + const regions: SourceLineRegion[] = [] + for (const el of nodes) { + const start = Number(el.getAttribute('data-source-line')) + if (!Number.isFinite(start)) continue + const endRaw = el.getAttribute('data-source-line-end') + const end = endRaw !== null && Number.isFinite(Number(endRaw)) ? Number(endRaw) : start + regions.push({ line: start, lineEnd: Math.max(start, end), el }) + } + regions.sort((a, b) => a.line - b.line) + return regions +} + +/** 阅读区中与源行号对应的元素(用于高亮闪烁)。 */ +export function findPreviewAnchorForLine( + article: HTMLElement, + line: number +): HTMLElement | null { + return finestElementForLine(article, line) ?? article.querySelector(`#${slugForLine(line)}`) +} + +function finestElementForLine(article: HTMLElement, line: number): HTMLElement | null { + const nodes = article.querySelectorAll(`[data-source-line="${line}"]`) + for (const el of nodes) { + const start = Number(el.getAttribute('data-source-line')) + if (start !== line) continue + const endRaw = el.getAttribute('data-source-line-end') + const end = endRaw !== null && Number.isFinite(Number(endRaw)) ? Number(endRaw) : start + if (end > start) continue + return el + } + return null +} + +/** + * 分栏阅读区:计算源行在 shell 内的垂直中心(px)。 + * `line` 为 0-based 源行号。 + */ +export function previewLineCenterInShell( + article: HTMLElement, + shell: HTMLElement, + line: number, + totalSourceLines: number +): number | null { + const shellRect = shell.getBoundingClientRect() + + const exact = finestElementForLine(article, line) + if (exact) { + const r = exact.getBoundingClientRect() + return r.top - shellRect.top + r.height / 2 + } + + const regions = collectSourceLineRegions(article) + if (regions.length === 0) { + const h = article.offsetHeight || 1 + return ((line + 0.5) / Math.max(1, totalSourceLines)) * h + } + + let region = regions[0]! + for (const r of regions) { + if (r.line <= line) region = r + else break + } + + if (line >= region.line && line <= region.lineEnd) { + const span = Math.max(1, region.lineEnd - region.line + 1) + const offset = Math.max(0, Math.min(line - region.line, span - 1)) + const frac = (offset + 0.5) / span + const blockRect = region.el.getBoundingClientRect() + return blockRect.top - shellRect.top + frac * blockRect.height + } + + const blockRect = region.el.getBoundingClientRect() + return blockRect.top - shellRect.top + blockRect.height / 2 +} + +export function scrollPreviewToSourceLine( + scrollEl: HTMLElement, + article: HTMLElement, + line: number, + behavior: ScrollBehavior = 'smooth', + totalSourceLines?: number +): HTMLElement | null { + const total = totalSourceLines ?? article.querySelectorAll('[data-source-line]').length + const shell = article.closest('.preview-shell') ?? article.parentElement + const anchor = findPreviewAnchorForLine(article, line) + if (!anchor && !shell) return null + + const scrollRect = scrollEl.getBoundingClientRect() + let top: number + if (anchor) { + const anchorRect = anchor.getBoundingClientRect() + top = anchorRect.top - scrollRect.top + scrollEl.scrollTop - 20 + anchor.classList.add('preview-anchor-flash') + window.setTimeout(() => anchor.classList.remove('preview-anchor-flash'), 1600) + } else if (shell instanceof HTMLElement) { + const center = previewLineCenterInShell(article, shell, line, total) + top = (center ?? 0) - 40 + } else { + return null + } + scrollEl.scrollTo({ top: Math.max(0, top), behavior }) + return anchor +} + +/** @deprecated 使用 previewLineCenterInShell */ +export function anchorCenterInShell(anchor: HTMLElement, shell: HTMLElement): number { + const shellRect = shell.getBoundingClientRect() + const r = anchor.getBoundingClientRect() + return r.top - shellRect.top + r.height / 2 +} diff --git a/src/renderer/src/outlineTree.ts b/src/renderer/src/outlineTree.ts new file mode 100644 index 0000000..69f8a1d --- /dev/null +++ b/src/renderer/src/outlineTree.ts @@ -0,0 +1,39 @@ +import type { OutlineItem } from './markdown' + +export type OutlineTreeNode = OutlineItem & { + id: string + children: OutlineTreeNode[] +} + +export function buildOutlineTree(items: OutlineItem[]): OutlineTreeNode[] { + const root: OutlineTreeNode[] = [] + const stack: OutlineTreeNode[] = [] + for (const item of items) { + const node: OutlineTreeNode = { + ...item, + id: `o-${item.line}`, + children: [] + } + while (stack.length > 0 && stack[stack.length - 1]!.level >= node.level) { + stack.pop() + } + if (stack.length === 0) root.push(node) + else stack[stack.length - 1]!.children.push(node) + stack.push(node) + } + return root +} + +export function collectBranchIds(nodes: OutlineTreeNode[]): string[] { + const ids: string[] = [] + const walk = (list: OutlineTreeNode[]): void => { + for (const n of list) { + if (n.children.length > 0) { + ids.push(n.id) + walk(n.children) + } + } + } + walk(nodes) + return ids +} diff --git a/src/renderer/src/pathLite.ts b/src/renderer/src/pathLite.ts new file mode 100644 index 0000000..3cead7e --- /dev/null +++ b/src/renderer/src/pathLite.ts @@ -0,0 +1,66 @@ +/** 轻量路径工具,供渲染进程 Markdown 使用(避免依赖 node:path 打包问题)。 */ + +export function dirnamePath(filePath: string): string { + const n = filePath.replace(/\\/g, '/') + const i = n.lastIndexOf('/') + if (i < 0) return '.' + const d = n.slice(0, i) + if (/^[A-Za-z]:$/.test(d)) return `${d}/` + return d || '/' +} + +/** 去掉 . /.. 的段落归一化(不含盘符)。 */ +export function normalizeDotSegments(pathWithoutDrive: string): string { + const segs = pathWithoutDrive.split('/').filter((s) => s && s !== '.') + const st: string[] = [] + for (const s of segs) { + if (s === '..') st.pop() + else st.push(s) + } + return st.join('/') +} + +/** 将相对 href 解析为绝对本地路径(正斜杠)。 */ +export function resolvePathFromBaseFile(baseFilePath: string, href: string): string { + let h = href.trim().replace(/\\/g, '/') + const q = h.indexOf('?') + if (q >= 0) h = h.slice(0, q) + const hash = h.indexOf('#') + if (hash >= 0) h = h.slice(0, hash) + + const baseNorm = baseFilePath.replace(/\\/g, '/') + const winBase = baseNorm.match(/^([A-Za-z]:)\/(.*)$/) + + if (/^[A-Za-z]:\//i.test(h)) { + const m = h.match(/^([A-Za-z]:\/)(.*)$/)! + return `${m[1]}${normalizeDotSegments(m[2] ?? '')}` + } + + if (h.startsWith('/')) { + if (winBase) { + return `${winBase[1]}/${normalizeDotSegments(h.slice(1))}` + } + return `/${normalizeDotSegments(h.slice(1))}` + } + + const dir = dirnamePath(baseNorm) + const joined = dir.endsWith('/') ? `${dir}${h}` : `${dir}/${h}` + + if (winBase) { + const m = joined.match(/^([A-Za-z]:\/)(.*)$/) + if (m) return `${m[1]}${normalizeDotSegments(m[2] ?? '')}` + } + if (joined.startsWith('/')) return `/${normalizeDotSegments(joined.slice(1))}` + return normalizeDotSegments(joined) +} + +/** 绝对路径 → file:// URL(Windows / Unix)。 */ +export function absolutePathToFileUrl(absPath: string): string { + const norm = absPath.replace(/\\/g, '/').trim() + if (!norm) return '' + if (/^[A-Za-z]:\//.test(norm)) { + return `file:///${encodeURI(norm)}` + } + const withLead = norm.startsWith('/') ? norm : `/${norm}` + return `file://${encodeURI(withLead)}` +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e8474a6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "useDefineForClassFields": true, + "types": ["vite/client"] + }, + "include": [ + "electron/**/*.ts", + "src/renderer/**/*.ts", + "src/renderer/**/*.tsx", + "src/renderer/index.html" + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..fe450f8 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022"], + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "allowSyntheticDefaultImports": true + }, + "include": ["electron.vite.config.ts"] +}