From 373d15ae031e134241e99e379f4a81cd20f0c656 Mon Sep 17 00:00:00 2001 From: sheheryarsoomro12 Date: Thu, 27 Aug 2026 21:16:01 +0500 Subject: [PATCH] Add Connect Desk source with gitignore for builds and secrets. Co-authored-by: Cursor --- .gitignore | 39 + DISTRIBUTION.md | 51 + README.md | 119 ++ build/icon.png | Bin 0 -> 124016 bytes main.js | 1039 +++++++++++++ package-lock.json | 3595 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 52 + preload.js | 193 +++ probe.js | 280 ++++ ui-preload.js | 30 + ui/index.html | 58 + ui/styles.css | 586 ++++++++ ui/ui.js | 436 ++++++ 13 files changed, 6478 insertions(+) create mode 100644 .gitignore create mode 100644 DISTRIBUTION.md create mode 100644 README.md create mode 100644 build/icon.png create mode 100644 main.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 preload.js create mode 100644 probe.js create mode 100644 ui-preload.js create mode 100644 ui/index.html create mode 100644 ui/styles.css create mode 100644 ui/ui.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0aaec3f --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +# Dependencies +node_modules/ + +# Packaged installers and unpacked Electron builds +dist/ +out/ +release/ + +# Logs and debug +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# OS junk +.DS_Store +Thumbs.db +Desktop.ini + +# Editor +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# Env and local secrets (never commit credentials) +.env +.env.* +credentials.json +accounts.json +*.pem +*.p12 +*.key + +# Electron / native +.electron-gyp +.cache/ +*.tsbuildinfo diff --git a/DISTRIBUTION.md b/DISTRIBUTION.md new file mode 100644 index 0000000..7c9c46a --- /dev/null +++ b/DISTRIBUTION.md @@ -0,0 +1,51 @@ +# Distributing Connect Desk + +The installers live in `dist/` after a build: + +| File | Platform | Notes | +|---|---|---| +| `Connect Desk Setup 1.9.0.exe` | Windows 10/11 (x64) | NSIS installer — runs on any normal Intel/AMD PC, and on Windows-on-ARM via emulation | +| `Connect Desk-1.9.0-arm64.dmg` | macOS (Apple Silicon) | Drag-to-Applications DMG | +| `Connect Desk-1.9.0.dmg` | macOS (Intel) | Drag-to-Applications DMG | + +Rebuild any time: + +```sh +npm run dist # Mac arm64 + Intel DMGs, and Windows x64 NSIS +npm run dist:mac # both Mac DMGs +npm run dist:win # Windows x64 installer (always --x64; this Mac is Apple Silicon) +``` + +## What recipients do + +**Windows:** run `Connect Desk Setup 1.9.0.exe`, pick an install folder, finish. A desktop and +Start-menu shortcut named "Connect Desk" are created; the app lives in the chosen folder as +`Connect Desk.exe`. + +**macOS:** open the DMG, drag **Connect Desk** into **Applications**, launch from there. + +Each installation starts empty: the recipient adds their accounts with **+ Add account** and signs in +with their own Connect credentials. Nothing from your machine — no accounts, no sessions, no +cookies — is inside the installer; only the app code ships. + +## The unsigned-app warnings (tell recipients this up front) + +These builds are not code-signed — there is no paid Apple Developer ID or Windows signing +certificate behind them — so both OSes show a one-time scare prompt: + +- **Windows SmartScreen**: "Windows protected your PC" → click **More info** → **Run anyway**. +- **macOS Gatekeeper**: "cannot be opened because the developer cannot be verified" → + **right-click the app → Open → Open**. Once is enough. + +This is expected for unsigned software and does not indicate a problem with the app. If you later +want prompt-free installs, that requires purchasing certificates: an Apple Developer ID +(~$99/year, plus notarization) and a Windows code-signing certificate — the config is ready for +both; only the certificates are missing. + +## Architecture cheat sheet + +- The build machine's CPU decides the default target. This Mac is Apple Silicon, so a plain + `--win nsis` build silently produced an **arm64** exe that ordinary PCs cannot run — always pass + `--x64` for Windows. +- For an Intel-Mac DMG: `npx electron-builder --mac dmg --x64`. For one DMG that runs on both: + `--universal` (roughly doubles the file size). diff --git a/README.md b/README.md new file mode 100644 index 0000000..e745505 --- /dev/null +++ b/README.md @@ -0,0 +1,119 @@ +# Connect Desk + +One window. Every Amazon Connect login signed in at the same time. + +```sh +npm start +``` + +## The problem it solves + +All your accounts live on the **same** Connect domain and differ only by login. A browser profile +holds exactly one session per domain, so signing in as account B silently evicts account A — which is +why you ended up with a separate Chrome profile per brand. + +Connect Desk gives every account its **own session partition** (its own cookie jar). Ten accounts stay +signed in simultaneously, side by side, in one window. Sessions persist across restarts: sign in once +per account and stay in. + +## Why it isn't a web page + +Connect sends `Content-Security-Policy: frame-ancestors 'self'`, which forbids any external site from +embedding the CCP in an iframe. Only the AWS account that *owns* the instance can allowlist an origin, +and these instances are owned by Amazon, not by you — so a browser-based dashboard is permanently +blocked. + +`frame-ancestors` restricts documents embedded **in a frame**. Here each account is a **top-level +view**, not a frame, so the rule doesn't apply. Verified: the CCP loads in each partition with zero CSP +errors, and no AWS permission of any kind is required. + +## The two instances + +Accounts live on one of two Amazon Connect instances (separate directories, separate logins): + +| Marketplaces | Instance | +|---|---| +| US, CA | `amazon-product-support-a67d8h.my.connect.aws/agent-app-v2` | +| UK, DE, FR, IT, ES, NL, BE, SE | `amazon-product-support-q42kxm.my.connect.aws/agent-app-v2` | + +Each account is assigned to an instance when you add it, shown as a **US** / **EU** chip on its row, +and changeable from the right-click menu. The URLs are stored in `accounts.json` under `instances` +if they ever need editing. + +## Using it + +- **Sidebar** lists your accounts. Click one to switch; the others keep running in the background and + keep receiving chats (background throttling is disabled for exactly this reason). +- **Incoming chat** is impossible to miss: a full-sidebar popup, a native OS notification (Mac and + Windows), a beep, taskbar/Dock flash, and the app switches to the ringing account. Click the popup + or the OS notification to jump there. This still works if you were looking at a different account. +- **+ Add account** first asks which instance (US/CA or UK/EU) the account belongs to, creates a new + isolated session, and drops you straight into naming it. Names also fill in automatically from the + signed-in agent; a manual rename always wins. +- **Right-click an account** for Rename, Set Available, Set Offline, instance selection, Reload, and + Remove (native OS menu). +- **Right-click in a chat** for spelling suggestions plus Cut / Copy / Paste. Spellcheck is on for + Connect composers (US + UK English). +- **All Available / All Offline** flip every signed-in account's status at once; a toast summarizes + which accounts changed and which need sign-in. +- **Sign in all / Sign out all** manage sessions in bulk. Sign-out ends each session server-side, + wipes the account's cookies, and **pauses auto-login for that account** (otherwise saved sign-ins + would immediately log it back in) — the dot goes grey with a "signed out" chip. Sign in all (or + per-account right-click → Sign in) resumes auto-login. This state survives app restarts. + +## Credentials + +By default none are stored — each account view shows Connect's own login page and the session cookie +stays inside that account's partition. + +**Saved sign-ins (optional, off until you use it):** the "Saved sign-ins…" panel stores a username + +password per account so accounts log themselves in — at startup and again whenever a session expires. + +Each row has **Save** (store this account's credentials) and **Sign in** (save, then log this one +account in immediately); the footer has **Save all**, **Sign in all**, and **Close**. Saving never +signs anything in on its own — the two are separate deliberate actions. "Sign in all" works through +the accounts **one at a time** with a gap between each, so a dozen simultaneous logins don't hit +Amazon's auth endpoint at once. + +How it's protected: + +- Passwords are encrypted with the OS keychain-backed key (`safeStorage`: macOS Keychain / Windows + DPAPI) and stored as ciphertext in `credentials.json`. Never plaintext; `accounts.json` never + contains secrets; the file cannot be decrypted on another computer or by another OS user. +- Credentials are released to an account's view **only** when that view is on the account's real + Amazon login host (`.my.connect.aws` / `.awsapps.com`) — enforced in the main + process, so no other page can request them. +- At most 2 automatic attempts per account per 5 minutes, so a wrong password can't be hammered into + an account lockout. +- "forget" in the panel deletes an account's saved sign-in; removing an account does too. +- If the form can't be filled, **nothing is submitted** and a toast says why — an empty submit would + burn an auth attempt and push the account toward a lockout. + +The sign-in page is a GWT app whose username box is `` — +`username` is not a valid HTML input type, so the field is matched by name/id, never by type. The +page also carries a hidden `#wdc_organization` decoy and a hidden `#wdc_mfa` second password field; +both are deliberately skipped. If Amazon ever enables MFA on an account, auto sign-in cannot complete +it and you'll need to sign in manually. + +The honest trade-off: anyone using your unlocked computer session can start the app and be signed in +— same as any password manager without a master password. Lock your machine. + +## Known limits + +- **One login per account, once.** AWS confirms there is no cross-account SSO without SAML federation, + which only the instance owner can configure. This app removes the *browser juggling*, not the logins. +- **Chat detection is best-effort.** It hooks Amazon Connect Streams (`window.connect`) in the CCP + iframe inside Agent Workspace, and falls back to scanning the page text if Streams never appears. + The fallback can break if Amazon restyles the CCP. Switching accounts and the sessions themselves + are unaffected either way. +- Ten-plus live CCPs is genuinely heavy. If it drags, remove accounts you aren't covering that day. + +## Layout + +| File | Role | +|---|---| +| `main.js` | Window, one partitioned `WebContentsView` per account, alerts, notifications | +| `probe.js` | Main-world Streams probe (injected into the CCP page and its iframes) | +| `preload.js` | Injected per account — relays contacts, status commands, login autofill | +| `ui-preload.js` | IPC bridge for the sidebar | +| `ui/` | Sidebar: account list, alerts, controls | diff --git a/build/icon.png b/build/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..33c3021861052834c05cdab0c7debd60e82a6e53 GIT binary patch literal 124016 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

~=*Oz>w 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

S^G@Kkl`@+j>eD>HLx}H5T0PfwoF@vK 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 Xp>M+wW_czJlvr$77vf*GHY)Rfy+BIb literal 0 HcmV?d00001 diff --git a/main.js b/main.js new file mode 100644 index 0000000..58172a1 --- /dev/null +++ b/main.js @@ -0,0 +1,1039 @@ +// Connect Desk — one window, many Amazon Connect logins. +// +// The problem this solves: all accounts live on the SAME Connect domain, so a +// normal browser profile can hold exactly one session — logging in as account B +// evicts account A. Here each account gets its own Electron session partition, +// i.e. its own cookie jar, so all of them stay signed in at once. +// +// Each account is a TOP-LEVEL WebContentsView, not an iframe. That matters: +// Connect sends `Content-Security-Policy: frame-ancestors 'self'`, which only +// restricts documents embedded in a frame. A top-level document isn't one, so +// nothing here needs an approved origin or any AWS permission. + +const { app, BaseWindow, WebContentsView, Notification, ipcMain, shell, dialog, Menu, safeStorage, webFrameMain } = require("electron"); +const path = require("node:path"); +const fs = require("node:fs"); +const { probeScript } = require("./probe"); + +const SIDEBAR_W = 268; + +let win; +let chrome; // the sidebar view +const views = new Map(); // account id -> WebContentsView +let activeId = null; + +// ---------- persisted config (labels only — never credentials) ---------- + +const configPath = () => path.join(app.getPath("userData"), "accounts.json"); + +// The two Amazon Connect instances. Every account belongs to exactly one — +// they are separate directories with separate logins. +const PRESET_INSTANCES = [ + { + id: "us-ca", + label: "US / CA", + short: "US", + url: "https://amazon-product-support-a67d8h.my.connect.aws/agent-app-v2", + }, + { + id: "eu", + label: "UK / EU (UK DE FR IT ES NL BE SE)", + short: "EU", + url: "https://amazon-product-support-q42kxm.my.connect.aws/agent-app-v2", + }, +]; + +const DEFAULTS = { + v: 3, + instances: structuredClone(PRESET_INSTANCES), + accounts: [{ id: "acct-1", fallback: "Account 1", instanceId: "us-ca" }], +}; + +function loadConfig() { + let cfg; + try { + cfg = { ...DEFAULTS, ...JSON.parse(fs.readFileSync(configPath(), "utf8")) }; + } catch { + cfg = structuredClone(DEFAULTS); + } + + let dirty = false; + + // v1 -> v2: labels written before rename worked were placeholders, not user + // choices. Demote them to `fallback` so login auto-detection can supersede + // them. A real rename after this sets `label`, which always wins. + if (!cfg.v) { + for (const a of cfg.accounts) { + if (a.label) { + a.fallback = a.label; + delete a.label; + } + } + cfg.v = 2; + dirty = true; + } + + // v2 -> v3: one global instanceUrl becomes per-account instances. Existing + // accounts were all on the US/CA instance (same domain), so their saved + // sessions carry over untouched — partitions are keyed by account id. + if (cfg.v < 3) { + delete cfg.instanceUrl; + for (const a of cfg.accounts) if (!a.instanceId) a.instanceId = "us-ca"; + cfg.v = 3; + dirty = true; + } + + // Seed / repair the instance list without clobbering user edits to URLs. + if (!Array.isArray(cfg.instances) || !cfg.instances.length) { + cfg.instances = structuredClone(PRESET_INSTANCES); + dirty = true; + } + for (const p of PRESET_INSTANCES) { + if (!cfg.instances.find((i) => i.id === p.id)) { + cfg.instances.push(structuredClone(p)); + dirty = true; + } + } + + // Scrub agent names that were scraped off login-form furniture by the old + // detector ("Remember username" is not a person). + for (const a of cfg.accounts) { + if (a.agentName && /remember|username|password|sign\s?in|log\s?in/i.test(a.agentName)) { + delete a.agentName; + dirty = true; + } + } + + if (dirty) { + try { + fs.writeFileSync(configPath(), JSON.stringify(cfg, null, 2)); + } catch {} + } + return cfg; +} + +function instanceFor(acct) { + return config.instances.find((i) => i.id === acct?.instanceId) || config.instances[0]; +} + +function urlFor(acct) { + return instanceFor(acct).url; +} + +// ---------- saved sign-ins (the only place credentials are handled) ---------- +// +// Passwords are encrypted with the OS keychain-backed key (safeStorage: macOS +// Keychain / Windows DPAPI) and stored as ciphertext in credentials.json — +// never plaintext, never inside accounts.json, and undecryptable on any other +// machine or OS user. Decryption happens only in this process, only at fill +// time, and only for a view sitting on the account's real Amazon login host. + +const credsPath = () => path.join(app.getPath("userData"), "credentials.json"); +let creds = {}; // accountId -> { username, passEnc(base64), autoLogin } + +function loadCreds() { + try { + creds = JSON.parse(fs.readFileSync(credsPath(), "utf8")); + } catch { + creds = {}; + } +} + +function saveCreds() { + fs.writeFileSync(credsPath(), JSON.stringify(creds, null, 2), { mode: 0o600 }); +} + +// The hosts a credential may ever be released to: the instance's own domain +// and its awsapps.com login twin. Nothing else, no matter what the view shows. +function loginHostsFor(acct) { + try { + const host = new URL(instanceFor(acct).url).hostname; + return [host, `${host.split(".")[0]}.awsapps.com`]; + } catch { + return []; + } +} + +// A wrong password must not be hammered into Amazon until the account locks: +// at most 2 automatic attempts per account per 5 minutes. +const fillAttempts = new Map(); + +ipcMain.handle("login:request", (event) => { + const entry = [...views.entries()].find(([, v]) => v.webContents.id === event.sender.id); + if (!entry) return null; + const [accountId, view] = entry; + const acct = config.accounts.find((a) => a.id === accountId); + const cred = creds[accountId]; + if (!acct || !cred?.passEnc || cred.autoLogin === false) return null; + // A deliberate sign-out stays signed out — otherwise auto-login would undo + // it the moment the login page appears. "Sign in" / "Sign in all" clears it. + if (acct.stayOut) return null; + + let pageHost = ""; + try { + pageHost = new URL(view.webContents.getURL()).hostname; + } catch {} + if (!loginHostsFor(acct).includes(pageHost)) return null; + + const now = Date.now(); + const recent = (fillAttempts.get(accountId) || []).filter((t) => now - t < 5 * 60e3); + if (recent.length >= 2) return null; + recent.push(now); + fillAttempts.set(accountId, recent); + + if (!safeStorage.isEncryptionAvailable()) return null; + try { + return { + username: cred.username || "", + password: safeStorage.decryptString(Buffer.from(cred.passEnc, "base64")), + }; + } catch { + return null; + } +}); + +ipcMain.handle("creds:list", () => + config.accounts.map((a) => ({ + id: a.id, + display: a.label || a.agentName || a.fallback || a.id, + instanceShort: instanceFor(a).short, + username: creds[a.id]?.username || "", + hasPassword: !!creds[a.id]?.passEnc, + })) +); + +ipcMain.handle("creds:save", (_e, entries, opts = {}) => { + if (!safeStorage.isEncryptionAvailable()) { + return { ok: false, error: "This OS user has no encryption keystore — sign-ins were NOT saved." }; + } + let saved = 0; + for (const en of entries || []) { + if (!config.accounts.find((a) => a.id === en.id)) continue; + if (en.clear) { + delete creds[en.id]; + continue; + } + const username = (en.username || "").trim(); + const password = typeof en.password === "string" ? en.password : ""; + const cur = creds[en.id] || {}; + if (!username && !password && !cur.passEnc) continue; + creds[en.id] = { + username: username || cur.username || "", + passEnc: password + ? safeStorage.encryptString(password).toString("base64") + : cur.passEnc || "", + autoLogin: true, + }; + if (creds[en.id].passEnc) saved++; + } + saveCreds(); + + // Saving alone never signs anything in — Save and Sign in are separate + // actions. It only refreshes the attempt budget so a corrected password can + // be tried immediately. + for (const en of entries || []) fillAttempts.delete(en.id); + pushState(); + return { ok: true, saved }; +}); + +function saveConfig(cfg) { + fs.writeFileSync(configPath(), JSON.stringify(cfg, null, 2)); +} + +let config = null; + +// ---------- layout ---------- + +function layout() { + if (!win) return; + const { width, height } = win.getContentBounds(); + chrome.setBounds({ x: 0, y: 0, width: SIDEBAR_W, height }); + const rest = { x: SIDEBAR_W, y: 0, width: Math.max(0, width - SIDEBAR_W), height }; + for (const [id, v] of views) { + if (id === activeId) { + v.setBounds(rest); + } else { + // Keep a full-size surface so the CCP keeps running, but park it off + // the window. On Windows, setVisible(false) WebContentsViews still + // steal mouse hits (All accounts buttons look dead) and can stall + // IPC/JS so Available / Offline / Sign in never reach the page. + v.setBounds({ x: -rest.width - 80, y: 0, width: rest.width, height: rest.height }); + } + v.setVisible(true); + } + // Account views are added after the sidebar, so re-stack chrome on top. + try { + win.contentView.addChildView(chrome); + } catch {} + if (process.env.CD_DEBUG) { + console.log("[layout]", JSON.stringify({ content: win.getContentBounds(), sidebar: chrome.getBounds(), pane: rest })); + } +} + +// ---------- account views ---------- + +function createAccountView(acct) { + const view = new WebContentsView({ + webPreferences: { + // The whole point: a dedicated, persistent cookie jar per account. + partition: `persist:${acct.id}`, + preload: path.join(__dirname, "preload.js"), + // Without this, Electron throttles hidden views and background accounts + // would stop receiving chats — which would defeat the purpose. + backgroundThrottling: false, + contextIsolation: true, + nodeIntegration: false, + // Agent Workspace keeps Streams (`window.connect`) in a CCP iframe. + // Preload + probe must run there or incoming chats are invisible to us. + nodeIntegrationInSubFrames: true, + spellcheck: true, + }, + }); + + const wc = view.webContents; + enableSpellcheck(wc.session); + attachCcpContextMenu(wc); + injectProbeOnFrames(wc); + + // Keep auth redirects inside this account's partition. Anything genuinely + // external goes to the real browser. + wc.setWindowOpenHandler(({ url }) => { + if (/\.(my\.connect\.aws|awsapps\.com|amazonaws\.com)/.test(new URL(url).hostname)) { + return { action: "allow" }; + } + shell.openExternal(url); + return { action: "deny" }; + }); + + wc.on("page-title-updated", () => pushState()); + wc.on("did-finish-load", () => { + retries.delete(acct.id); + pushState(); + }); + + // Loading many CCPs at once can time one out. Retry with backoff rather than + // leaving a dead panel that needs a manual reload. + wc.on("did-fail-load", (_e, code, desc, url, isMainFrame) => { + if (code === -3 || !isMainFrame) return; // -3 = aborted, usually a redirect + const n = (retries.get(acct.id) || 0) + 1; + retries.set(acct.id, n); + send("account:error", { id: acct.id, message: `${desc} (${code})`, attempt: n }); + if (n <= 4) { + setTimeout(() => { + if (views.has(acct.id) && !wc.isDestroyed()) wc.loadURL(urlFor(acct)); + }, n * 3000); + } + pushState(); + }); + + // Park off-screen until activate()/layout() places it. Do not use + // setVisible(false) — on Windows that view still eats sidebar clicks. + view.setBounds({ x: -2000, y: 0, width: 800, height: 600 }); + view.setVisible(true); + win.contentView.addChildView(view); + views.set(acct.id, view); + lockZoom(wc, acct.id); + try { + win.contentView.addChildView(chrome); + } catch {} + return view; +} + +const retries = new Map(); + +function enableSpellcheck(ses) { + try { + ses.setSpellCheckerEnabled(true); + } catch {} + try { + const available = ses.availableSpellCheckerLanguages || []; + const want = ["en-US", "en-GB"].filter((l) => !available.length || available.includes(l)); + if (want.length) ses.setSpellCheckerLanguages(want); + } catch {} +} + +function attachCcpContextMenu(wc) { + wc.on("context-menu", (event, params) => { + event.preventDefault?.(); + const template = []; + for (const suggestion of params.dictionarySuggestions || []) { + template.push({ + label: suggestion, + click: () => wc.replaceMisspelling(suggestion), + }); + } + if (params.misspelledWord) { + if (template.length) template.push({ type: "separator" }); + template.push({ + label: "Add to Dictionary", + click: () => wc.session.addWordToSpellCheckerDictionary(params.misspelledWord), + }); + } + if (template.length) template.push({ type: "separator" }); + const flags = params.editFlags || {}; + template.push( + { role: "cut", enabled: !!flags.canCut }, + { role: "copy", enabled: !!flags.canCopy }, + { role: "paste", enabled: !!flags.canPaste }, + { role: "selectAll", enabled: flags.canSelectAll !== false } + ); + Menu.buildFromTemplate(template).popup(); + }); +} + +function injectProbeOnFrames(wc) { + const inject = (frame) => { + try { + if (!frame || frame.isDestroyed?.()) return; + frame.executeJavaScript(probeScript).catch(() => {}); + } catch {} + }; + wc.on("did-frame-finish-load", (_e, _isMainFrame, frameProcessId, frameRoutingId) => { + try { + inject(webFrameMain.fromId(frameProcessId, frameRoutingId)); + } catch {} + }); +} + +function sendToAllFrames(wc, channel, ...args) { + if (!wc || wc.isDestroyed()) return; + // Always hit the top frame — webContents.send is reliable on Windows. + // frame.send to CCP iframes is extra; if it no-ops we still have the + // preload's postMessage forward into same-origin iframes. + try { + wc.send(channel, ...args); + } catch {} + try { + const frames = wc.mainFrame?.framesInSubtree || []; + const seen = new Set(); + for (const frame of frames) { + try { + if (!frame || frame.isDestroyed?.()) continue; + const key = `${frame.processId}:${frame.routingId}`; + if (seen.has(key)) continue; + seen.add(key); + frame.send(channel, ...args); + } catch {} + } + } catch {} +} + +function bringToFront() { + if (!win) return; + if (win.isMinimized()) win.restore(); + win.show(); + try { + win.moveTop(); + } catch {} + if (process.platform === "darwin") app.dock?.bounce("informational"); +} + +// The sidebar and the CCPs are fixed layouts — any zoom (trackpad pinch, or a +// stray Cmd+= from browser muscle memory) scales the page past its view and +// clips it. Worse, Electron persists zoom per origin, so it survives restarts. +// Lock every webContents at 100%. +function lockZoom(wc, tag) { + const reset = () => { + const z = wc.getZoomFactor(); + if (z !== 1 && process.env.CD_DEBUG) console.log(`[zoom] ${tag} was ${z}, resetting`); + wc.setZoomFactor(1); + try { + const p = wc.setVisualZoomLevelLimits(1, 1); // disables pinch zoom + p?.catch?.(() => {}); + } catch {} + }; + wc.on("did-finish-load", reset); + wc.on("zoom-changed", reset); // ctrl/cmd + mouse-wheel zoom +} + +// Start the accounts a beat apart so a dozen CCPs don't all hit the same host +// in the same instant. +function loadStaggered(ids, gap = 1200) { + ids.forEach((id, i) => { + setTimeout(() => { + const wc = views.get(id)?.webContents; + const acct = config.accounts.find((a) => a.id === id); + if (wc && !wc.isDestroyed()) wc.loadURL(urlFor(acct)); + }, i * gap); + }); +} + +function activate(id) { + if (!views.has(id)) return; + clearReplyAlerts(id); + activeId = id; + layout(); + pushState(); +} + +function clearReplyAlerts(accountId) { + for (const key of [...alerts.keys()]) { + const a = alerts.get(key); + if (a && a.accountId === accountId && a.kind === "reply") alerts.delete(key); + } +} + +function lookingAt(accountId) { + return activeId === accountId && win && !win.isDestroyed() && win.isFocused(); +} + +function hasWaiting(accountId) { + for (const a of alerts.values()) { + if (a.accountId === accountId && a.kind === "waiting") return true; + } + return false; +} + +function stopFlash() { + try { + win?.flashFrame?.(false); + } catch {} +} + +function announceIncoming(accountId, contactId, queue) { + if (hasWaiting(accountId)) return; + const name = displayName(accountId); + const key = `${accountId}:${contactId}`; + alerts.set(key, { + accountId, + label: name, + contactId, + kind: "waiting", + queue: queue || "", + }); + try { + const n = new Notification({ + title: `Incoming chat — ${name}`, + body: queue ? `Queue: ${queue}` : "A customer is waiting. Click to open.", + silent: false, + }); + n.on("click", () => { + bringToFront(); + activate(accountId); + }); + n.show(); + } catch {} + try { + shell.beep(); + } catch {} + bringToFront(); + try { + win?.flashFrame?.(true); + } catch {} + if (activeId !== accountId) activate(accountId); + toast(`Incoming chat — ${name}`); + pushState(); +} + +const INCOMING_PAGE_JS = `(() => { try { return /incoming chat|accept chat|reject chat/i.test((document.body && document.body.innerText) || ""); } catch (e) { return false; } })()`; + +function pollIncomingPages() { + for (const [id, view] of views) { + const wc = view.webContents; + if (!wc || wc.isDestroyed() || wc.isLoading()) continue; + wc.executeJavaScript(INCOMING_PAGE_JS, true) + .then((hit) => { + const key = `${id}:dom-incoming`; + if (hit) announceIncoming(id, "dom-incoming", ""); + else if (alerts.get(key)?.contactId === "dom-incoming") { + alerts.delete(key); + if (![...alerts.values()].some((a) => a.kind === "waiting")) stopFlash(); + pushState(); + } + }) + .catch(() => {}); + } +} + +function removeAccount(id) { + const v = views.get(id); + if (v) { + win.contentView.removeChildView(v); + v.webContents.close(); + views.delete(id); + } + live.delete(id); + for (const key of [...alerts.keys()]) if (key.startsWith(`${id}:`)) alerts.delete(key); + delete creds[id]; + saveCreds(); + fillAttempts.delete(id); + config.accounts = config.accounts.filter((a) => a.id !== id); + saveConfig(config); + if (activeId === id) { + const next = config.accounts[0]; + activeId = null; + if (next) activate(next.id); + } + pushState(); +} + +// ---------- state -> sidebar ---------- + +const alerts = new Map(); // `${accountId}:${contactId}` -> {accountId, label, contactId, queue} +const live = new Map(); // accountId -> {stateName, stateType, signedIn} (runtime only) + +function send(channel, payload) { + if (chrome && !chrome.webContents.isDestroyed()) chrome.webContents.send(channel, payload); +} + +function accountBadge(id) { + let n = 0; + for (const a of alerts.values()) { + if (a.accountId !== id) continue; + n += a.kind === "reply" ? a.count || 1 : 1; + } + return n; +} + +function pushState() { + send("state", { + instances: config.instances.map(({ id, label, short }) => ({ id, label, short })), + activeId, + accounts: config.accounts.map((a) => { + const wc = views.get(a.id)?.webContents; + const lv = live.get(a.id) || {}; + const inst = instanceFor(a); + return { + ...a, + // What the sidebar shows: a manual rename always wins, otherwise the + // agent name detected after login, otherwise the placeholder. + display: a.label || a.agentName || a.fallback || a.id, + instanceId: inst.id, + instanceShort: inst.short, + instanceLabel: inst.label, + loading: wc ? wc.isLoading() : false, + title: wc && !wc.isDestroyed() ? wc.getTitle() : "", + waiting: accountBadge(a.id), + stateName: lv.stateName || "", + stateType: lv.stateType || "", + signedIn: lv.signedIn, + }; + }), + alerts: [...alerts.values()], + }); + + let total = 0; + for (const a of alerts.values()) total += a.kind === "reply" ? a.count || 1 : 1; + if (process.platform === "darwin") app.dock?.setBadge(total ? String(total) : ""); +} + +// ---------- IPC ---------- + +ipcMain.handle("get-state", () => pushState()); +ipcMain.handle("activate", (_e, id) => activate(id)); +ipcMain.handle("reload", (_e, id) => views.get(id)?.webContents.reload()); + +ipcMain.handle("add-account", (_e, instanceId) => { + const id = `acct-${Date.now().toString(36)}`; + const inst = config.instances.find((i) => i.id === instanceId) || config.instances[0]; + // No name is asked for up front — it fills itself in from the agent name once + // you sign in, and can be overridden any time. + const acct = { + id, + fallback: `Account ${config.accounts.length + 1}`, + instanceId: inst.id, + }; + config.accounts.push(acct); + saveConfig(config); + createAccountView(acct); + loadStaggered([id], 0); + activate(id); + return id; +}); + +async function confirmRemoveAccount(id) { + const a = config.accounts.find((x) => x.id === id); + const name = a?.label || a?.agentName || a?.fallback || id; + const { response } = await dialog.showMessageBox(win, { + type: "warning", + buttons: ["Cancel", "Remove"], + defaultId: 0, + cancelId: 0, + message: `Remove "${name}"?`, + detail: "Its saved session is discarded, so you'll need to sign in again to use it.", + }); + if (response === 1) removeAccount(id); +} + +ipcMain.handle("remove-account", (_e, id) => confirmRemoveAccount(id)); + +ipcMain.handle("rename-account", (_e, { id, label }) => { + const a = config.accounts.find((x) => x.id === id); + if (!a) return; + const next = (label || "").trim(); + // Clearing the name hands control back to auto-detection. + if (next) a.label = next; + else delete a.label; + saveConfig(config); + pushState(); +}); + +// Move an account to the other Connect instance. Its partition (and any saved +// session cookies for either domain) stays intact — only the loaded URL changes. +function setAccountInstance(id, instanceId) { + const a = config.accounts.find((x) => x.id === id); + const inst = config.instances.find((i) => i.id === instanceId); + if (!a || !inst || a.instanceId === inst.id) return; + a.instanceId = inst.id; + delete a.agentName; // the old instance's agent identity no longer applies + saveConfig(config); + live.delete(id); + const wc = views.get(id)?.webContents; + if (wc && !wc.isDestroyed()) wc.loadURL(inst.url); + pushState(); +} + +ipcMain.handle("set-account-instance", (_e, { id, instanceId }) => setAccountInstance(id, instanceId)); + +// Fired by preload.js when an account sees a contact arrive or leave, or once +// it works out which agent is signed in. +ipcMain.on("contact", (event, msg) => { + const entry = + [...views.entries()].find(([, v]) => v.webContents.id === event.sender.id) || + [...views.entries()].find(([, v]) => v.webContents === event.sender); + if (!entry) return; + const [accountId] = entry; + + if (msg.type === "agent") { + fillAttempts.delete(accountId); // signed in — reset the auto-fill budget + live.set(accountId, { ...(live.get(accountId) || {}), signedIn: true }); + const a = config.accounts.find((x) => x.id === accountId); + if (a && msg.name && a.agentName !== msg.name) { + a.agentName = msg.name; + saveConfig(config); + } + pushState(); + return; + } + if (msg.type === "state") { + live.set(accountId, { + ...(live.get(accountId) || {}), + stateName: msg.stateName, + stateType: msg.stateType, + signedIn: true, + }); + pushState(); + return; + } + if (msg.type === "auth") { + live.set(accountId, { ...(live.get(accountId) || {}), signedIn: msg.signedIn }); + pushState(); + return; + } + if (msg.type === "status-result") { + handleStatusResult(accountId, msg); + return; + } + if (msg.type === "autofill-failed") { + // Nothing was submitted, so no auth attempt was spent. Say so plainly + // rather than leaving the account sitting on a filled-but-idle form. + toast(`${displayName(accountId)}: auto sign-in couldn't fill the form (${msg.reason}) — sign in manually`); + return; + } + if (msg.type === "detection") return; + + const name = displayName(accountId); + const key = `${accountId}:${msg.contactId}`; + + if (msg.type === "accepted") { + const cur = alerts.get(key); + if (cur && cur.kind !== "reply") alerts.delete(key); + pushState(); + return; + } + + if (msg.type === "reply") { + if (lookingAt(accountId)) return; + const prev = alerts.get(key); + const count = (prev && prev.kind === "reply" ? prev.count || 1 : 0) + 1; + alerts.set(key, { + accountId, + label: name, + contactId: msg.contactId, + kind: "reply", + queue: "New message", + text: msg.text || "New message", + count, + }); + const n = new Notification({ + title: `New message — ${name}`, + body: msg.text || "A customer replied.", + }); + n.on("click", () => { + bringToFront(); + activate(accountId); + }); + n.show(); + if (process.platform === "darwin") app.dock?.bounce("informational"); + toast(`New message — ${name}`); + pushState(); + return; + } + + if (msg.type === "incoming") { + announceIncoming(accountId, msg.contactId, msg.queue || ""); + return; + } else if (msg.type === "gone") { + alerts.delete(key); + if (![...alerts.values()].some((a) => a.kind === "waiting")) stopFlash(); + } + pushState(); +}); + +ipcMain.handle("focus-alert", (_e, accountId) => activate(accountId)); + +ipcMain.on("show-account-menu", (_e, id) => { + const a = config.accounts.find((x) => x.id === id); + if (!a) return; + const instId = instanceFor(a).id; + const template = [ + { label: "Rename", click: () => send("menu:action", { type: "rename", id }) }, + { label: "Saved sign-in…", click: () => send("menu:action", { type: "creds" }) }, + { type: "separator" }, + { + label: "Set Available", + click: () => sendToAllFrames(views.get(id)?.webContents, "cd-set-status", "routable"), + }, + { + label: "Set Offline", + click: () => sendToAllFrames(views.get(id)?.webContents, "cd-set-status", "offline"), + }, + { type: "separator" }, + { + label: "Sign in", + click: () => { + const auto = signInAccount(id); + saveConfig(config); + pushState(); + if (!auto) { + toast(`${displayName(id)}: no saved sign-in — enter it on the login page or in Saved sign-ins`); + } + }, + }, + { + label: "Sign out", + click: async () => { + await signOutAccount(id); + saveConfig(config); + pushState(); + toast(`${displayName(id)}: signed out`); + }, + }, + { type: "separator" }, + ...config.instances.map((inst) => ({ + label: inst.label, + type: "radio", + checked: inst.id === instId, + click: () => setAccountInstance(id, inst.id), + })), + { type: "separator" }, + { label: "Reload", click: () => views.get(id)?.webContents.reload() }, + { label: "Remove account…", click: () => confirmRemoveAccount(id) }, + ]; + Menu.buildFromTemplate(template).popup(); +}); + +ipcMain.handle("show-instance-menu", () => { + return new Promise((resolve) => { + let done = false; + const finish = (value) => { + if (done) return; + done = true; + resolve(value); + }; + const template = (config.instances || []).map((inst) => ({ + label: inst.label, + click: () => finish(inst.id), + })); + Menu.buildFromTemplate(template).popup({ callback: () => finish(null) }); + }); +}); + +// ---------- agent status (single + bulk) ---------- + +const toast = (text) => send("toast", { text }); +let bulk = null; // {kind, results: Map, total, timer} + +function displayName(accountId) { + const a = config.accounts.find((x) => x.id === accountId); + return a ? a.label || a.agentName || a.fallback || a.id : accountId; +} + +function flushBulk() { + if (!bulk) return; + clearTimeout(bulk.timer); + const missing = bulk.total - bulk.results.size; + const parts = [...bulk.results.values()]; + if (missing > 0) parts.push(`${missing} account(s) did not respond`); + toast(parts.join(" · ") || "No accounts responded"); + bulk = null; +} + +function handleStatusResult(accountId, msg) { + const text = msg.ok + ? `${displayName(accountId)}: ${msg.state || "done"} ✓` + : `${displayName(accountId)}: ${msg.error}`; + if (bulk && bulk.kind === msg.kind) { + if (bulk.results.has(accountId)) return; + bulk.results.set(accountId, text); + if (bulk.results.size >= bulk.total) flushBulk(); + return; + } + toast(text); +} + +// ---------- sign-out / sign-in (single + bulk) ---------- + +// Full sign-out: end the Connect session server-side, then wipe this account's +// partition (cookies incl. the awsapps SSO refresh token), then show the login +// page again. stayOut keeps auto-login from immediately reversing it. +async function signOutAccount(id) { + const acct = config.accounts.find((a) => a.id === id); + const view = views.get(id); + if (!acct || !view) return; + acct.stayOut = true; + const wc = view.webContents; + try { + const origin = new URL(instanceFor(acct).url).origin; + await Promise.race([ + wc.loadURL(`${origin}/logout`).catch(() => {}), + new Promise((r) => setTimeout(r, 3000)), + ]); + await wc.session.clearStorageData().catch(() => {}); + } catch {} + live.set(id, { signedIn: false }); + for (const key of [...alerts.keys()]) if (key.startsWith(`${id}:`)) alerts.delete(key); + fillAttempts.delete(id); + if (!wc.isDestroyed()) wc.loadURL(urlFor(acct)).catch(() => {}); +} + +function signInAccount(id) { + const acct = config.accounts.find((a) => a.id === id); + if (!acct) return false; + delete acct.stayOut; + fillAttempts.delete(id); + const wc = views.get(id)?.webContents; + const canAuto = !!creds[id]?.passEnc; + if (wc && !wc.isDestroyed() && live.get(id)?.signedIn !== true) { + wc.loadURL(urlFor(acct)).catch(() => {}); // fresh load; autofill takes it from here + } + return canAuto; +} + +ipcMain.handle("signout", async (_e, id) => { + await signOutAccount(id); + saveConfig(config); + pushState(); + toast(`${displayName(id)}: signed out`); +}); + +ipcMain.handle("signout-all", async () => { + await Promise.all(config.accounts.map((a) => signOutAccount(a.id))); + saveConfig(config); + pushState(); + toast(`Signed out ${config.accounts.length} account(s). Auto-login is paused until you sign in again.`); +}); + +ipcMain.handle("signin", (_e, id) => { + const auto = signInAccount(id); + saveConfig(config); + pushState(); + if (!auto) toast(`${displayName(id)}: no saved sign-in — enter it on the login page or in Saved sign-ins`); +}); + +// One by one, with a gap — firing every login at Amazon's auth endpoint in the +// same instant risks throttling, and a stuck one shouldn't block the rest. +let signInAllRunning = false; + +ipcMain.handle("signin-all", async () => { + if (signInAllRunning) return; + const targets = config.accounts.filter((a) => live.get(a.id)?.signedIn !== true); + if (!targets.length) { + toast("Every account is already signed in."); + return; + } + const withCreds = targets.filter((a) => creds[a.id]?.passEnc).length; + if (!withCreds) { + toast("No saved sign-ins yet — add them under Saved sign-ins…"); + } + + signInAllRunning = true; + toast(`Signing in ${targets.length} account(s), one at a time…`); + try { + for (let i = 0; i < targets.length; i++) { + const a = targets[i]; + delete a.stayOut; + fillAttempts.delete(a.id); + const wc = views.get(a.id)?.webContents; + if (wc && !wc.isDestroyed()) wc.loadURL(urlFor(a)).catch(() => {}); + pushState(); + if (i < targets.length - 1) await new Promise((r) => setTimeout(r, 3000)); + } + } finally { + signInAllRunning = false; + saveConfig(config); + pushState(); + } +}); + +ipcMain.handle("set-status", (_e, { id, kind }) => { + sendToAllFrames(views.get(id)?.webContents, "cd-set-status", kind); +}); + +ipcMain.handle("set-status-all", (_e, kind) => { + flushBulk(); // close out any previous batch first + bulk = { + kind, + results: new Map(), + total: views.size, + // Accounts sitting on a login page fail fast; a hung one shouldn't stall + // the summary forever. + timer: setTimeout(flushBulk, 12000), + }; + toast(kind === "offline" ? "Setting all accounts to Offline…" : "Setting all accounts to Available…"); + for (const v of views.values()) sendToAllFrames(v.webContents, "cd-set-status", kind); +}); + +// ---------- boot ---------- + +// Windows: notifications only appear when the app has an explicit user-model id. +app.setAppUserModelId("com.aiteam.connectdesk"); + +app.whenReady().then(() => { + config = loadConfig(); + loadCreds(); + + // No View menu: its zoom/reload roles are exactly what scrambled the sidebar. + // Edit stays — sign-in forms need paste. appMenu is macOS-only. + const template = []; + if (process.platform === "darwin") template.push({ role: "appMenu" }); + template.push({ role: "editMenu" }, { role: "windowMenu" }); + Menu.setApplicationMenu(Menu.buildFromTemplate(template)); + + win = new BaseWindow({ width: 1440, height: 900, minWidth: 880, minHeight: 560, title: "Connect Desk" }); + + chrome = new WebContentsView({ + webPreferences: { preload: path.join(__dirname, "ui-preload.js"), contextIsolation: true }, + }); + win.contentView.addChildView(chrome); + lockZoom(chrome.webContents, "sidebar"); + if (process.env.CD_DEBUG) { + chrome.webContents.on("console-message", (_e, _level, msg) => + console.log("[sidebar]", msg) + ); + } + chrome.webContents.loadFile(path.join(__dirname, "ui", "index.html")); + + for (const a of config.accounts) createAccountView(a); + // Active account first, so the one you're looking at is ready soonest. + if (config.accounts[0]) activate(config.accounts[0].id); + loadStaggered(config.accounts.map((a) => a.id)); + + layout(); + win.on("resize", layout); + win.on("focus", stopFlash); + chrome.webContents.on("did-finish-load", pushState); + setInterval(pollIncomingPages, 1500); +}); + +app.on("window-all-closed", () => app.quit()); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..63c2359 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3595 @@ +{ + "name": "connect-desk", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "connect-desk", + "version": "1.0.0", + "license": "UNLICENSED", + "devDependencies": { + "electron": "^43.2.0", + "electron-builder": "^26.0.12" + } + }, + "node_modules/@electron-internal/extract-zip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@electron-internal/extract-zip/-/extract-zip-1.0.5.tgz", + "integrity": "sha512-+bqFCP98pLI0Tt0XQo1TmlXtwjWchISndDOxCkEcIuUgXWpBnLyRI+2DU+mesvnMMX6L1XDqYNA0lXNDHd/yiA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@electron/asar": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz", + "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.1.6", + "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.npmjs.org/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.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "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.npmjs.org/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.npmjs.org/@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.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/get": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-5.1.0.tgz", + "integrity": "sha512-3kSBtG8ObcTVfXanm5vVJ6UnBLEVmVsRk1M+vGqCuMBV+XLCbJYuWQful+yIy0GQDsSlK0kHEriEHn7SPk4EnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^3.0.0", + "graceful-fs": "^4.2.11", + "progress": "^2.0.3", + "semver": "^7.6.3", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=22.12.0" + }, + "optionalDependencies": { + "undici": "^7.24.4" + } + }, + "node_modules/@electron/notarize": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz", + "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", + "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.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/osx-sign": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@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/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/@electron/rebuild": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-4.2.0.tgz", + "integrity": "sha512-RKL/O+jGoXJMxrx/5771y1n0xTKmFuOYGO3gMmwypBM6rsH0kou0mswwdXA2JrhIkE4xyC7v9vGk0n6NPzgOxQ==", + "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.npmjs.org/@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.npmjs.org/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.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@electron/universal/node_modules/fs-extra": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz", + "integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==", + "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/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@electron/windows-sign": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz", + "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "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.4.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz", + "integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==", + "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/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@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/@malept/cross-spawn-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", + "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", + "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.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", + "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.0", + "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.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@noble/hashes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.8.0.tgz", + "integrity": "sha512-7YT0U/ze0tF2QOBbE15gKZwy5tvgGyLRiRHLzhlbOpf7BT032oBSd0haZqXn5W6l26WLlu3dyxzjM+2638/z2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/json-schema": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", + "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@peculiar/utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz", + "integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/webcrypto": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.7.1.tgz", + "integrity": "sha512-ODOov0sGMJMf3jPonOkgGqPknTsu+DdQ7kD++gz8aI+aFMOMHFbWAA2taqXXVTdP+OTOQR/znGvSpmkeI0WTYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/json-schema": "^1.1.12", + "@peculiar/utils": "^2.0.2", + "tslib": "^2.8.1", + "webcrypto-core": "^1.9.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@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.npmjs.org/@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/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@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/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@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.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", + "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.13", + "resolved": "https://registry.npmjs.org/@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/abbrev": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/app-builder-lib": { + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.15.3.tgz", + "integrity": "sha512-2VnyWkqsP5v5XbBhL3tD5Syx8iNPBYsoU7kY4S2fz7wg8Rj/nztWKCUzGKaFRTv0Xwf3/H058CR1Kvtd/3lRow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@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.4", + "@electron/universal": "2.0.3", + "@malept/flatpak-bundler": "^0.4.0", + "@noble/hashes": "^2.2.0", + "@peculiar/webcrypto": "^1.7.1", + "@types/fs-extra": "9.0.13", + "ajv": "^8.18.0", + "asn1js": "^3.0.10", + "async-exit-hook": "^2.0.1", + "builder-util": "26.15.3", + "builder-util-runtime": "9.7.0", + "chromium-pickle-js": "^0.2.0", + "ci-info": "4.3.1", + "debug": "^4.3.4", + "dotenv": "^16.4.5", + "dotenv-expand": "^11.0.6", + "ejs": "^3.1.8", + "electron-publish": "26.15.3", + "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.2.5", + "pkijs": "^3.4.0", + "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", + "unzipper": "^0.12.3", + "which": "^5.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "dmg-builder": "26.15.3", + "electron-builder-squirrel-windows": "26.15.3" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@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.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^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.npmjs.org/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.npmjs.org/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/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/app-builder-lib/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/app-builder-lib/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/app-builder-lib/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/asn1js": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", + "integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.5", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/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/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/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.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builder-util": { + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.15.3.tgz", + "integrity": "sha512-q2hn7Mbo2nFNkVekPiHFx6Nfo3hURmES3tfBn+k5Pqxl2RkmP3QGqZUhH/q9Pch/4G05NRhPjDlVj1O8q4Txvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.6", + "builder-util-runtime": "9.7.0", + "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" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/builder-util-runtime": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.7.0.tgz", + "integrity": "sha512-g/kR520giAFYkSXTzcmF3kqQq7wi8F6N6SzeDgZrqTBN+VHdmgWOyTdD1yD7AATDId/yXLvuP34CxW46/BwCdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/bytestreamjs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", + "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/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/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/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.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-dirname": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "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.npmjs.org/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/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/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.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "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.npmjs.org/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.15.3", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.15.3.tgz", + "integrity": "sha512-O3zJUFUYHJKgzPqioHxfxzBzlSC1eXCSr79gMSBKBP5AgjjpmrydMsMLotEg9fAJF36vdUncb+4ndRNxoPdlSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "26.15.3", + "builder-util": "26.15.3", + "fs-extra": "^10.1.0", + "js-yaml": "^4.1.0" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron": { + "version": "43.2.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-43.2.0.tgz", + "integrity": "sha512-80zvrgG7ZRXD+tD0IyLvrnN9n+veSxadMRsMaC9wKKP3iUbtC7rGM8+dVuCmOb0Rrwwv8ESW4awnUZh9Hbp1fA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-internal/extract-zip": "^1.0.1", + "@electron/get": "^5.0.0", + "@types/node": "^24.9.0" + }, + "bin": { + "electron": "cli.js", + "install-electron": "install.js" + }, + "engines": { + "node": ">= 22.12.0" + } + }, + "node_modules/electron-builder": { + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.15.3.tgz", + "integrity": "sha512-a1KM5heqS3gQCZzizXEI8RjJy3QVogULPdeSknt76uLDpBIW/HDGsMg/XgP0riP6PI9COsRvFITKKGDqA8fJxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "26.15.3", + "builder-util": "26.15.3", + "builder-util-runtime": "9.7.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "dmg-builder": "26.15.3", + "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.15.3", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.15.3.tgz", + "integrity": "sha512-Jc19XPV9y9+2bAdZPkXuVNGNIEFBq9poHC61l8Kv6FdK7DRG3+Ic0rerC0DXOaeHNz8yW0fg/JnF8GQROOF5MA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "26.15.3", + "builder-util": "26.15.3", + "electron-winstaller": "5.4.0" + } + }, + "node_modules/electron-publish": { + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.15.3.tgz", + "integrity": "sha512-g/2bn8YTavY4cuS5F+jOS7zmZbXXBV8KZ8yHKfJjFPoKtzBqrpCdNPxBd3tqdBwP7BVd0lGzf7Bk2s0KesWZ4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/fs-extra": "^9.0.11", + "aws4": "^1.13.2", + "builder-util": "26.15.3", + "builder-util-runtime": "9.7.0", + "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-winstaller": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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/electron-winstaller/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "peer": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-winstaller/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/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.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "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.npmjs.org/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/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "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.npmjs.org/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.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "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.npmjs.org/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.npmjs.org/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/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/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/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/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.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isbinaryfile": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.7.tgz", + "integrity": "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/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.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/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-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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": "6.2.1", + "resolved": "https://registry.npmjs.org/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/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/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.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-abi": { + "version": "4.33.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.33.0.tgz", + "integrity": "sha512-vLBWCKb+7LWsX+TbfzWOkw0W81m377tyx3hOweBTjO43CXZnRGS1/JPWs20fr0PgZyDXk6ROYrylsEycK8raDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.6.3" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/node-api-version": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.1.tgz", + "integrity": "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + } + }, + "node_modules/node-gyp": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.4.0.tgz", + "integrity": "sha512-OMcPNvqTCFUnNaBlmdgq+lfNqY7gTiSmNRDjY3uAXRyudeKZEZxu3CLtjMQrx4zZxCX2b/mpNqTtwuCJgXhHkw==", + "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/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/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/undici": { + "version": "6.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz", + "integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/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-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nopt": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pe-library": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-0.4.1.tgz", + "integrity": "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkijs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.0.tgz", + "integrity": "sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@noble/hashes": "1.4.0", + "asn1js": "^3.0.6", + "bytestreamjs": "^2.0.1", + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/pkijs/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/postject": { + "version": "1.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "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.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/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/read-binary-file-arch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", + "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "bin": { + "read-binary-file-arch": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resedit": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/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/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/sanitize-filename": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.4.tgz", + "integrity": "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==", + "dev": true, + "license": "WTFPL OR ISC", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/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/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/stat-mode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", + "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/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.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "7.5.22", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", + "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.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/temp": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/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.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", + "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^10.0.0" + } + }, + "node_modules/tiny-async-pool": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "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.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/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/undici": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unzipper": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.5.tgz", + "integrity": "sha512-tXYOi9R57Uj/2Z25SOs5RRSzq886MBQj2gY8dPL+xl/kv6s6SvByoKfAtvfVeEuhntWDgjd2o9p2lb4TVPAz0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "~3.7.2", + "duplexer2": "~0.1.4", + "fs-extra": "11.3.1", + "graceful-fs": "^4.2.2", + "node-int64": "^0.4.0" + } + }, + "node_modules/unzipper/node_modules/fs-extra": { + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", + "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/webcrypto-core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.9.2.tgz", + "integrity": "sha512-gsXecm82UQNlTBURJGuqOWy1Ww08S3kZUcr3aOJS02Pk0xLtkfeUAVC0u0xhgdonFme80edSJUIJyuvL/7250Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/json-schema": "^1.1.12", + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + } + }, + "node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "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.npmjs.org/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.npmjs.org/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.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "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.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..0c80387 --- /dev/null +++ b/package.json @@ -0,0 +1,52 @@ +{ + "name": "connect-desk", + "version": "1.9.0", + "description": "One window for every Amazon Connect account — simultaneous sign-ins, unified chat alerts, bulk status control.", + "main": "main.js", + "scripts": { + "start": "electron .", + "dist:mac": "electron-builder --mac dmg --arm64 --x64", + "dist:win": "electron-builder --win nsis --x64", + "dist": "npm run dist:mac && npm run dist:win" + }, + "author": "AI Team", + "license": "UNLICENSED", + "private": true, + "devDependencies": { + "electron": "^43.2.0", + "electron-builder": "^26.0.12" + }, + "build": { + "appId": "com.aiteam.connectdesk", + "productName": "Connect Desk", + "directories": { + "buildResources": "build", + "output": "dist" + }, + "files": [ + "main.js", + "preload.js", + "probe.js", + "ui-preload.js", + "ui/**" + ], + "mac": { + "category": "public.app-category.business", + "target": [ + "dmg" + ] + }, + "win": { + "target": [ + "nsis" + ] + }, + "nsis": { + "oneClick": false, + "allowToChangeInstallationDirectory": true, + "createDesktopShortcut": true, + "createStartMenuShortcut": true, + "shortcutName": "Connect Desk" + } + } +} diff --git a/preload.js b/preload.js new file mode 100644 index 0000000..1ed8177 --- /dev/null +++ b/preload.js @@ -0,0 +1,193 @@ +// Injected into every account view (top page and CCP iframes). Three jobs: +// 1. Detect the signed-in agent (name + state) and report it to main. +// 2. Detect contacts arriving/leaving for the unified alert strip. +// 3. Execute status commands ("go Available"/"go Offline") inside the CCP. +// +// The probe must run in the PAGE's main world to see `window.connect`. It is +// injected with webFrame.executeJavaScript — NOT a + + diff --git a/ui/styles.css b/ui/styles.css new file mode 100644 index 0000000..b5f1158 --- /dev/null +++ b/ui/styles.css @@ -0,0 +1,586 @@ +:root { + --bg: #14171a; + --surface: #1b1f24; + --surface-2: #222831; + --line: #2c333d; + --text: #e6edf3; + --muted: #8b98a5; + --accent: #4493f8; + --ok: #3fb950; + --warn: #d29922; + --err: #f85149; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + height: 100vh; + display: grid; + grid-template-rows: auto auto 1fr auto; + /* One column, hard-capped at the body's width. Without this the implicit + column sizes to max-content — the nowrap instance URL once blew it out to + ~390px inside a 268px view, pushing the right side of every row and the + second footer button past the visible edge. */ + grid-template-columns: minmax(0, 1fr); + background: var(--bg); + color: var(--text); + font: 13px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + user-select: none; + overflow-y: hidden; + /* clip, not hidden: hidden containers can still be scrolled programmatically + (e.g. by focusing the rename input), which shoved the whole sidebar + sideways. clip forbids scrolling entirely. */ + overflow-x: clip; +} + +header, +#alerts, +#accounts, +footer { + overflow-x: clip; + min-width: 0; /* grid items may never dictate the column width */ +} + +header { + padding: 14px 14px 10px; + border-bottom: 1px solid var(--line); + -webkit-app-region: drag; +} + +h1 { + margin: 0 0 3px; + font-size: 13px; + font-weight: 600; +} + +#instance { + font: 10px ui-monospace, monospace; + color: var(--muted); + cursor: pointer; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + -webkit-app-region: no-drag; +} + +#instance:hover { + color: var(--accent); +} + +/* --- unified alerts --- */ +#alerts { + padding: 8px; + border-bottom: 1px solid var(--line); + background: var(--surface); + max-height: 190px; + overflow-y: auto; +} + +#alerts .empty { + color: var(--muted); + font-size: 11px; + padding: 2px 4px; +} + +.alert { + padding: 7px 9px; + margin-bottom: 5px; + border: 1px solid var(--accent); + border-radius: 6px; + background: #12283f; + cursor: pointer; + animation: pulse 1.6s ease-in-out infinite; +} + +.alert:last-child { + margin-bottom: 0; +} + +.alert b { + display: block; +} + +.alert span { + color: var(--muted); + font-size: 11px; +} + +@keyframes pulse { + 50% { + border-color: #7cc0ff; + } +} + +/* --- accounts --- */ +#accounts { + padding: 8px; + overflow-y: auto; +} + +.acct { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 9px; + margin-bottom: 3px; + border: 1px solid transparent; + border-radius: 6px; + cursor: pointer; +} + +.acct:hover { + background: var(--surface-2); +} + +.acct.active { + background: var(--surface-2); + border-color: var(--line); +} + +.dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--muted); + flex: none; +} + +.dot.loading { + background: var(--warn); +} +.dot.ready { + background: var(--ok); +} +.dot.err { + background: var(--err); +} +.dot.off { + background: #566270; +} + +.acct .state { + flex: none; + font-size: 10px; + color: var(--muted); +} + +/* which Connect instance the account lives on */ +.acct .inst { + flex: none; + padding: 1px 5px; + border: 1px solid var(--line); + border-radius: 4px; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.4px; + color: var(--muted); +} + +.acct:hover .inst { + display: none; /* make room for the tool buttons */ +} + +.acct:hover .state { + display: none; /* make room for the tool buttons */ +} + +.acct .label { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.acct .label.placeholder { + color: var(--muted); + font-style: italic; +} + +.rename { + flex: 1; + min-width: 0; + padding: 3px 6px; + border: 1px solid var(--accent); + border-radius: 4px; + background: #0d1117; + color: var(--text); + font: inherit; + outline: none; +} + +.acct .badge { + min-width: 17px; + padding: 0 5px; + border-radius: 9px; + background: var(--accent); + color: #06101d; + font-size: 10px; + font-weight: 700; + text-align: center; +} + +.acct .tools { + display: none; + gap: 4px; +} + +.acct:hover .tools { + display: flex; +} + +.acct .tools button { + border: 0; + background: none; + color: var(--muted); + cursor: pointer; + padding: 0 2px; + font-size: 12px; +} + +.acct .tools button:hover { + color: var(--text); +} + +/* --- footer --- */ +footer { + padding: 10px; + border-top: 1px solid var(--line); + -webkit-app-region: no-drag; +} + +footer button { + -webkit-app-region: no-drag; +} + +#bulk-label { + margin-bottom: 5px; + font-size: 10px; + font-weight: 600; + letter-spacing: 0.4px; + text-transform: uppercase; + color: var(--muted); +} + +#bulk, +#bulk2 { + display: flex; + gap: 6px; + margin-bottom: 8px; +} + +/* appearance:none everywhere — if a button ever loses its styling it must + degrade to a dark rectangle, never a white UA-default widget. */ +#bulk button, +#bulk2 button, +#add, +#signins { + appearance: none; + -webkit-appearance: none; + border: 1px solid var(--line); + border-radius: 6px; + background: var(--surface-2); + color: var(--text); + font: inherit; + cursor: pointer; +} + +#bulk button { + flex: 1 1 0; + min-width: 0; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 6px; + white-space: nowrap; + padding: 7px 4px; + font-size: 12px; +} + +#bulk button:hover, +#bulk2 button:hover, +#add:hover, +#signins:hover { + border-color: var(--accent); +} + +#bulk button:active, +#bulk2 button:active, +#add:active, +#signins:active { + background: #2a313b; +} + +#bulk2 button { + flex: 1 1 0; + min-width: 0; + white-space: nowrap; + padding: 6px 4px; + font-size: 12px; +} + +#signins { + width: 100%; + padding: 6px; + margin-top: 6px; + font-size: 12px; + color: var(--muted); +} + +.bdot { + width: 8px; + height: 8px; + border-radius: 50%; + flex: none; +} + +.bdot.av { + background: var(--ok); +} + +.bdot.off { + background: #566270; +} + +#add { + width: 100%; + padding: 7px; +} + +#hint { + margin-top: 8px; + font-size: 10px; + line-height: 1.45; + color: var(--muted); +} + +#credit { + margin-top: 10px; + padding-top: 8px; + border-top: 1px solid var(--line); + font-size: 10px; + letter-spacing: 0.3px; + text-align: center; + color: var(--muted); +} + +/* --- toast --- */ +#toast { + position: fixed; + left: 10px; + right: 10px; + bottom: 10px; + z-index: 40; + padding: 8px 10px; + background: #0d1117; + border: 1px solid var(--line); + border-radius: 8px; + font-size: 11px; + line-height: 1.4; +} + +#toast[hidden] { + display: none; +} + +#incoming-pop { + position: fixed; + inset: 0; + z-index: 60; + display: flex; + align-items: center; + justify-content: center; + padding: 16px; + background: rgba(8, 10, 12, 0.82); +} + +#incoming-pop[hidden] { + display: none; +} + +.incoming-pop-card { + width: 100%; + padding: 16px 14px 14px; + border: 2px solid #3fb950; + border-radius: 10px; + background: #12283f; + text-align: center; + animation: pulse 1.2s ease-in-out infinite; +} + +.incoming-pop-kicker { + font-size: 11px; + font-weight: 700; + letter-spacing: 0.8px; + text-transform: uppercase; + color: #7ee787; +} + +#incoming-pop-name { + margin: 8px 0 14px; + font-size: 16px; + font-weight: 700; + line-height: 1.3; +} + +#incoming-pop-go { + appearance: none; + -webkit-appearance: none; + width: 100%; + padding: 10px; + border: 0; + border-radius: 8px; + background: #3fb950; + color: #0d1117; + font: inherit; + font-weight: 700; + cursor: pointer; +} + +/* --- saved sign-ins panel --- */ +#creds { + position: fixed; + inset: 0; + z-index: 50; + overflow-y: auto; + overflow-x: clip; + padding: 14px; + background: var(--bg); +} + +#creds[hidden] { + display: none; +} + +.creds-head { + font-size: 13px; + font-weight: 600; + margin-bottom: 6px; +} + +.creds-note { + font-size: 10px; + line-height: 1.5; + color: var(--muted); + margin-bottom: 12px; +} + +.creds-row { + margin-bottom: 12px; +} + +.creds-row.cleared { + opacity: 0.35; +} + +.creds-name { + font-size: 12px; + font-weight: 600; + margin-bottom: 4px; +} + +.creds-line { + display: flex; + flex-direction: column; + gap: 4px; +} + +.creds-line .rename { + width: 100%; +} + +/* per-account action bar */ +.creds-rowbar { + display: flex; + align-items: center; + gap: 6px; + margin-top: 5px; +} + +.creds-rowbar button { + appearance: none; + padding: 3px 9px; + border: 1px solid var(--line); + border-radius: 5px; + background: var(--surface-2); + color: var(--text); + font: inherit; + font-size: 11px; + cursor: pointer; +} + +.creds-rowbar button:hover { + border-color: var(--accent); +} + +.creds-rowbar button.primary { + border-color: var(--accent); + background: var(--accent); + color: #06101d; + font-weight: 600; +} + +.creds-status { + flex: 1; + min-width: 0; + font-size: 10px; + color: var(--ok); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.creds-forget { + flex: none; + border: 0; + background: none; + color: var(--muted); + font-size: 10px; + cursor: pointer; + padding: 0; +} + +.creds-forget:hover { + color: var(--err); +} + +.creds-row.cleared .creds-forget { + color: var(--err); + font-weight: 700; +} + +.creds-actions { + display: flex; + gap: 6px; + margin-top: 16px; + padding-top: 12px; + border-top: 1px solid var(--line); +} + +.creds-actions button { + appearance: none; + flex: 1 1 0; + min-width: 0; + white-space: nowrap; + padding: 8px 4px; + border: 1px solid var(--line); + border-radius: 6px; + background: var(--surface-2); + color: var(--text); + font: inherit; + font-size: 12px; + cursor: pointer; +} + +.creds-actions button:hover { + border-color: var(--accent); +} + +.creds-actions button.primary { + border-color: var(--accent); + background: var(--accent); + color: #06101d; + font-weight: 600; +} diff --git a/ui/ui.js b/ui/ui.js new file mode 100644 index 0000000..4922a27 --- /dev/null +++ b/ui/ui.js @@ -0,0 +1,436 @@ +const $alerts = document.getElementById("alerts"); +const $accounts = document.getElementById("accounts"); +const $instance = document.getElementById("instance"); +const $toast = document.getElementById("toast"); +const $incomingPop = document.getElementById("incoming-pop"); +const $incomingPopName = document.getElementById("incoming-pop-name"); +const $incomingPopGo = document.getElementById("incoming-pop-go"); + +// Electron has no window.prompt(), so renames happen through an inline input. +// `editing` survives re-renders so the field isn't wiped mid-typing. +let editing = null; +let lastState = { accounts: [], alerts: [] }; + +// Belt & braces alongside overflow-x:clip — nothing may ever scroll the +// sidebar sideways (a focused input once did, which clipped all content). +function resetScroll() { + for (const el of [document.scrollingElement, document.body, $accounts]) { + if (el && el.scrollLeft) el.scrollLeft = 0; + } +} + +/* ---------------- alerts ---------------- */ + +function renderAlerts(alerts) { + $alerts.innerHTML = ""; + if (!alerts.length) { + const e = document.createElement("div"); + e.className = "empty"; + e.textContent = "No waiting chats"; + $alerts.append(e); + return; + } + for (const a of alerts) { + const el = document.createElement("div"); + el.className = "alert"; + const b = document.createElement("b"); + b.textContent = a.label; + const s = document.createElement("span"); + s.textContent = a.kind === "reply" ? a.text || "New message" : a.queue || "waiting"; + el.append(b, s); + el.onclick = () => api.focusAlert(a.accountId); + $alerts.append(el); + } +} + +/* ---------------- rename editor ---------------- */ + +function startEdit(id) { + editing = id; + render(lastState); +} + +function commitEdit(id, value) { + if (editing !== id) return; + editing = null; + api.renameAccount(id, value); +} + +// Native popups (Chromium autofill, macOS spelling/substitution) anchor to text +// inputs and float OVER the window — an orphaned one is what once appeared as a +// white box across the footer. Disable everything that can summon one. +function plainInput() { + const input = document.createElement("input"); + input.autocomplete = "off"; + input.spellcheck = false; + input.setAttribute("autocapitalize", "off"); + input.setAttribute("autocorrect", "off"); + return input; +} + +function buildEditor(a) { + const input = plainInput(); + input.className = "rename"; + input.value = a.label || a.agentName || ""; + input.placeholder = a.agentName || "Account name"; + input.onclick = (e) => e.stopPropagation(); + input.onkeydown = (e) => { + e.stopPropagation(); + if (e.key === "Enter") commitEdit(a.id, input.value); + if (e.key === "Escape") { + editing = null; + render(lastState); + } + }; + input.onblur = () => commitEdit(a.id, input.value); + setTimeout(() => { + input.focus({ preventScroll: true }); // focus scrolling is what broke alignment + input.select(); + resetScroll(); + }, 0); + return input; +} + +/* ---------------- account rows ---------------- */ + +function dotClass(a) { + if (a.loading) return "dot loading"; + if (a.stayOut && a.signedIn !== true) return "dot off"; // deliberate sign-out, not an error + if (a.signedIn === false) return "dot err"; + if (a.stateType === "routable") return "dot ready"; + if (a.stateType === "offline") return "dot off"; + if (a.agentName) return "dot ready"; + return "dot"; +} + +function stateText(a) { + if (a.stayOut && a.signedIn !== true) return "signed out"; + if (a.signedIn === false) return "sign in"; + return a.stateName || ""; +} + +function buildRow(a, activeId) { + const el = document.createElement("div"); + el.className = "acct" + (a.id === activeId ? " active" : ""); + el.onclick = () => api.activate(a.id); + el.oncontextmenu = (e) => { + e.preventDefault(); + api.showAccountMenu(a.id); + }; + + const dot = document.createElement("span"); + dot.className = dotClass(a); + el.append(dot); + + if (editing === a.id) { + el.append(buildEditor(a)); + return el; + } + + const label = document.createElement("span"); + label.className = "label"; + label.textContent = a.display; + if (!a.label && !a.agentName) label.classList.add("placeholder"); + label.title = + (a.agentName ? `Signed in as ${a.agentName}` : "Not signed in yet") + + ` — ${a.instanceLabel || ""}`; + label.ondblclick = (e) => { + e.stopPropagation(); + startEdit(a.id); + }; + el.append(label); + + // Which Connect instance this account lives on (US / EU). + if (a.instanceShort) { + const inst = document.createElement("span"); + inst.className = "inst"; + inst.textContent = a.instanceShort; + inst.title = a.instanceLabel; + el.append(inst); + } + + const st = stateText(a); + if (st) { + const chip = document.createElement("span"); + chip.className = "state"; + chip.textContent = st; + el.append(chip); + } + + if (a.waiting) { + const badge = document.createElement("span"); + badge.className = "badge"; + badge.textContent = a.waiting; + el.append(badge); + } + + const tools = document.createElement("span"); + tools.className = "tools"; + for (const [glyph, title, fn] of [ + ["✎", "Rename", () => startEdit(a.id)], + ["⟳", "Reload", () => api.reload(a.id)], + ["✕", "Remove account", () => api.removeAccount(a.id)], + ]) { + const b = document.createElement("button"); + b.textContent = glyph; + b.title = title; + b.onclick = (e) => { + e.stopPropagation(); + fn(); + }; + tools.append(b); + } + el.append(tools); + return el; +} + +/* ---------------- render ---------------- */ + +function renderIncomingPop(alerts) { + const waiting = (alerts || []).filter((a) => a.kind !== "reply"); + if (!waiting.length) { + $incomingPop.hidden = true; + $incomingPopGo.onclick = null; + return; + } + $incomingPop.hidden = false; + $incomingPopName.textContent = waiting.map((a) => a.label).join(" · "); + $incomingPopGo.onclick = (e) => { + e.stopPropagation(); + api.focusAlert(waiting[0].accountId); + }; +} + +function render(state) { + lastState = state; + $instance.textContent = (state.instances || []).map((i) => i.label).join(" · "); + renderAlerts(state.alerts); + renderIncomingPop(state.alerts); + $accounts.innerHTML = ""; + for (const a of state.accounts) $accounts.append(buildRow(a, state.activeId)); + resetScroll(); +} + +api.onState(render); +api.onError(({ message }) => console.warn("account error:", message)); +api.onMenuAction((a) => { + if (a.type === "rename") startEdit(a.id); + if (a.type === "creds") openCreds(); +}); + +/* ---------------- toast ---------------- */ + +let toastTimer; +api.onToast(({ text }) => { + $toast.textContent = text; + $toast.hidden = false; + clearTimeout(toastTimer); + toastTimer = setTimeout(() => ($toast.hidden = true), 6000); +}); + +/* ---------------- top-level controls ---------------- */ + +// Every account belongs to one Connect instance, so adding starts by picking +// which one — then straight into naming, as before. +const $add = document.getElementById("add"); +$add.onclick = async (e) => { + e.stopPropagation(); + const instances = lastState.instances || []; + const create = async (instId) => { + const id = await api.addAccount(instId); + if (id) startEdit(id); + }; + if (instances.length <= 1) return void create(instances[0]?.id); + const instId = await api.showInstanceMenu(); + if (instId) create(instId); +}; + +document.getElementById("all-available").onclick = () => api.setStatusAll("routable"); +document.getElementById("all-offline").onclick = () => api.setStatusAll("offline"); +document.getElementById("all-signin").onclick = () => api.signInAll(); +document.getElementById("all-signout").onclick = () => api.signOutAll(); + +/* ---------------- saved sign-ins panel ---------------- */ + +const $creds = document.getElementById("creds"); + +function closeCreds() { + $creds.hidden = true; + $creds.innerHTML = ""; // never leave typed passwords sitting in the DOM +} + +function showToast(text, ms = 6000) { + $toast.textContent = text; + $toast.hidden = false; + clearTimeout(toastTimer); + toastTimer = setTimeout(() => ($toast.hidden = true), ms); +} + +async function openCreds() { + const rows = await api.credsList(); + $creds.innerHTML = ""; + + const head = document.createElement("div"); + head.className = "creds-head"; + head.textContent = "Saved sign-ins"; + const note = document.createElement("div"); + note.className = "creds-note"; + note.textContent = + "Stored encrypted on this computer only (OS keychain). Filled only on the official " + + "Amazon Connect sign-in page for each account's instance. Leave a password blank to keep " + + "the one already saved."; + $creds.append(head, note); + + const cleared = new Set(); + const inputs = new Map(); // id -> {u, p, status} + + // Collects one row (or every row) into the shape creds:save expects. + const entryFor = (id) => { + const { u, p } = inputs.get(id); + return { id, username: u.value, password: p.value || null, clear: cleared.has(id) }; + }; + const allEntries = () => [...inputs.keys()].map(entryFor); + + const flash = (id, text) => { + const s = inputs.get(id)?.status; + if (!s) return; + s.textContent = text; + clearTimeout(s._t); + s._t = setTimeout(() => (s.textContent = ""), 4000); + }; + + // After saving, the password box is empty again but a secret now exists — + // reflect that so the row doesn't look unsaved. + const markSaved = (id) => { + const { p } = inputs.get(id); + p.value = ""; + p.placeholder = "•••••• saved — blank keeps it"; + }; + + const saveOne = async (id) => { + const res = await api.credsSave([entryFor(id)]); + if (!res?.ok) return showToast(res?.error || "Saving failed.", 8000); + if (cleared.has(id)) { + cleared.delete(id); + inputs.get(id).row.classList.remove("cleared"); + inputs.get(id).p.placeholder = "password"; + flash(id, "forgotten"); + } else { + markSaved(id); + flash(id, "saved ✓"); + } + return true; + }; + + for (const r of rows) { + const row = document.createElement("div"); + row.className = "creds-row"; + + const name = document.createElement("div"); + name.className = "creds-name"; + name.textContent = `${r.display} · ${r.instanceShort}`; + + const u = plainInput(); + u.className = "rename"; + u.placeholder = "login username / email"; + u.value = r.username; + + const p = plainInput(); + p.className = "rename"; + p.type = "password"; + p.placeholder = r.hasPassword ? "•••••• saved — blank keeps it" : "password"; + + const bar = document.createElement("div"); + bar.className = "creds-rowbar"; + + const bSave = document.createElement("button"); + bSave.type = "button"; + bSave.textContent = "Save"; + bSave.title = "Save this account's sign-in"; + bSave.onclick = () => saveOne(r.id); + + const bSignIn = document.createElement("button"); + bSignIn.type = "button"; + bSignIn.className = "primary"; + bSignIn.textContent = "Sign in"; + bSignIn.title = "Save, then sign this account in with these credentials"; + bSignIn.onclick = async () => { + if (!(await saveOne(r.id))) return; + flash(r.id, "signing in…"); + api.signIn(r.id); + }; + + const forget = document.createElement("button"); + forget.type = "button"; + forget.className = "creds-forget"; + forget.textContent = "forget"; + forget.title = "Mark this saved sign-in for deletion, then Save"; + forget.onclick = () => { + if (cleared.has(r.id)) { + cleared.delete(r.id); + row.classList.remove("cleared"); + } else { + cleared.add(r.id); + row.classList.add("cleared"); + } + }; + + const status = document.createElement("span"); + status.className = "creds-status"; + + bar.append(bSave, bSignIn, status, forget); + + inputs.set(r.id, { u, p, status, row }); + const line = document.createElement("div"); + line.className = "creds-line"; + line.append(u, p); + row.append(name, line, bar); + $creds.append(row); + } + + const actions = document.createElement("div"); + actions.className = "creds-actions"; + + const saveAll = document.createElement("button"); + saveAll.type = "button"; + saveAll.textContent = "Save all"; + saveAll.onclick = async () => { + const res = await api.credsSave(allEntries()); + if (!res?.ok) return showToast(res?.error || "Saving failed.", 8000); + for (const id of inputs.keys()) { + if (cleared.has(id)) continue; + markSaved(id); + } + cleared.clear(); + for (const { row } of inputs.values()) row.classList.remove("cleared"); + showToast(`Saved sign-ins for ${res.saved} account(s).`); + }; + + const signInAll = document.createElement("button"); + signInAll.type = "button"; + signInAll.className = "primary"; + signInAll.textContent = "Sign in all"; + signInAll.onclick = async () => { + const res = await api.credsSave(allEntries()); + if (!res?.ok) return showToast(res?.error || "Saving failed.", 8000); + closeCreds(); + api.signInAll(); + }; + + const close = document.createElement("button"); + close.type = "button"; + close.textContent = "Close"; + close.onclick = closeCreds; + + actions.append(saveAll, signInAll, close); + $creds.append(actions); + + $creds.hidden = false; +} + +document.getElementById("signins").onclick = openCreds; +addEventListener("keydown", (e) => { + if (e.key === "Escape" && !$creds.hidden) closeCreds(); +}); + +api.getState();